diff options
Diffstat (limited to 'lib/Frontend')
26 files changed, 1667 insertions, 886 deletions
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 882d400..4a63d76 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -12,19 +12,19 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTConsumers.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceManager.h" #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" -#include "llvm/Module.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/IR/Module.h" #include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -59,9 +59,12 @@ namespace { bool TraverseDecl(Decl *D) { if (D != NULL && filterMatches(D)) { - Out.changeColor(llvm::raw_ostream::BLUE) << - (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n"; - Out.resetColor(); + bool ShowColors = Out.has_colors(); + if (ShowColors) + Out.changeColor(raw_ostream::BLUE); + Out << (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n"; + if (ShowColors) + Out.resetColor(); if (Dump) D->dump(Out); else @@ -101,7 +104,8 @@ namespace { bool shouldWalkTypesOfTypeLocs() const { return false; } virtual bool VisitNamedDecl(NamedDecl *D) { - Out << D->getQualifiedNameAsString() << "\n"; + D->printQualifiedName(Out); + Out << '\n'; return true; } @@ -459,6 +463,10 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "<class template> " << *CTD << '\n'; break; } + case Decl::OMPThreadPrivate: { + Out << "<omp threadprivate> " << '"' << *I << "\"\n"; + break; + } default: Out << "DeclKind: " << DK << '"' << *I << "\"\n"; llvm_unreachable("decl unhandled"); diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp index 31b1df4..bfb3083 100644 --- a/lib/Frontend/ASTMerge.cpp +++ b/lib/Frontend/ASTMerge.cpp @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTUnit.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTImporter.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" using namespace clang; diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 5576854..c1115ae 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -12,40 +12,40 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTUnit.h" -#include "clang/AST/ASTContext.h" #include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclVisitor.h" -#include "clang/AST/TypeOrdering.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeOrdering.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/Utils.h" -#include "clang/Serialization/ASTReader.h" -#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" +#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Atomic.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Timer.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" -#include "llvm/Support/CrashRecoveryContext.h" -#include <cstdlib> +#include "llvm/Support/Path.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" #include <cstdio> +#include <cstdlib> #include <sys/stat.h> using namespace clang; @@ -103,7 +103,7 @@ static llvm::sys::SmartMutex<false> &getOnDiskMutex() { return M; } -static void cleanupOnDiskMapAtExit(void); +static void cleanupOnDiskMapAtExit(); typedef llvm::DenseMap<const ASTUnit *, OnDiskData *> OnDiskDataMap; static OnDiskDataMap &getOnDiskDataMap() { @@ -116,7 +116,7 @@ static OnDiskDataMap &getOnDiskDataMap() { return M; } -static void cleanupOnDiskMapAtExit(void) { +static void cleanupOnDiskMapAtExit() { // Use the mutex because there can be an alive thread destroying an ASTUnit. llvm::MutexGuard Guard(getOnDiskMutex()); OnDiskDataMap &M = getOnDiskDataMap(); @@ -155,7 +155,7 @@ static void removeOnDiskEntry(const ASTUnit *AU) { } } -static void setPreambleFile(const ASTUnit *AU, llvm::StringRef preambleFile) { +static void setPreambleFile(const ASTUnit *AU, StringRef preambleFile) { getOnDiskData(AU).PreambleFile = preambleFile; } @@ -270,7 +270,7 @@ void ASTUnit::setPreprocessor(Preprocessor *pp) { PP = pp; } /// \brief Determine the set of code-completion contexts in which this /// declaration should be shown. -static unsigned getDeclShowContexts(NamedDecl *ND, +static unsigned getDeclShowContexts(const NamedDecl *ND, const LangOptions &LangOpts, bool &IsNestedNameSpecifier) { IsNestedNameSpecifier = false; @@ -310,9 +310,9 @@ static unsigned getDeclShowContexts(NamedDecl *ND, Contexts |= (1LL << CodeCompletionContext::CCC_EnumTag); // Part of the nested-name-specifier in C++0x. - if (LangOpts.CPlusPlus0x) + if (LangOpts.CPlusPlus11) IsNestedNameSpecifier = true; - } else if (RecordDecl *Record = dyn_cast<RecordDecl>(ND)) { + } else if (const RecordDecl *Record = dyn_cast<RecordDecl>(ND)) { if (Record->isUnion()) Contexts |= (1LL << CodeCompletionContext::CCC_UnionTag); else @@ -356,8 +356,9 @@ void ASTUnit::CacheCodeCompletionResults() { typedef CodeCompletionResult Result; SmallVector<Result, 8> Results; CachedCompletionAllocator = new GlobalCodeCompletionAllocator; + CodeCompletionTUInfo CCTUInfo(CachedCompletionAllocator); TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator, - getCodeCompletionTUInfo(), Results); + CCTUInfo, Results); // Translate global code completions into cached completions. llvm::DenseMap<CanQualType, unsigned> CompletionTypes; @@ -369,7 +370,7 @@ void ASTUnit::CacheCodeCompletionResults() { CachedCodeCompletionResult CachedResult; CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema, *CachedCompletionAllocator, - getCodeCompletionTUInfo(), + CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration, Ctx->getLangOpts(), @@ -435,7 +436,7 @@ void ASTUnit::CacheCodeCompletionResults() { CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema, *CachedCompletionAllocator, - getCodeCompletionTUInfo(), + CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = RemainingContexts; CachedResult.Priority = CCP_NestedNameSpecifier; @@ -458,7 +459,7 @@ void ASTUnit::CacheCodeCompletionResults() { CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema, *CachedCompletionAllocator, - getCodeCompletionTUInfo(), + CCTUInfo, IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = (1LL << CodeCompletionContext::CCC_TopLevel) @@ -541,8 +542,8 @@ public: return false; this->TargetOpts = new TargetOptions(TargetOpts); - Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), - *this->TargetOpts); + Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), + &*this->TargetOpts); updated(); return false; @@ -572,6 +573,11 @@ private: // Initialize the ASTContext Context.InitBuiltinTypes(*Target); + + // We didn't have access to the comment options when the ASTContext was + // constructed, so register them now. + Context.getCommentCommandTraits().registerCommentOptions( + LangOpt.CommentOpts); } }; @@ -655,8 +661,7 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags, if (CaptureDiagnostics) Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics); Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(), - ArgEnd-ArgBegin, - ArgBegin, Client, + Client, /*ShouldOwnClient=*/true, /*ShouldCloneClient=*/false); } else if (CaptureDiagnostics) { @@ -791,11 +796,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, Counter)); switch (Reader->ReadAST(Filename, serialization::MK_MainFile, - ASTReader::ARR_None)) { + SourceLocation(), ASTReader::ARR_None)) { case ASTReader::Success: break; case ASTReader::Failure: + case ASTReader::Missing: case ASTReader::OutOfDate: case ASTReader::VersionMismatch: case ASTReader::ConfigurationMismatch: @@ -842,7 +848,8 @@ class MacroDefinitionTrackerPPCallbacks : public PPCallbacks { public: explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { } - virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { + virtual void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) { Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash); } }; @@ -1081,7 +1088,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // Create the target instance. Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), - Clang->getTargetOpts())); + &Clang->getTargetOpts())); if (!Clang->hasTarget()) { delete OverrideMainBuffer; return true; @@ -1550,7 +1557,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Create the target instance. Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), - Clang->getTargetOpts())); + &Clang->getTargetOpts())); if (!Clang->hasTarget()) { llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); @@ -1688,7 +1695,30 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) { } StringRef ASTUnit::getMainFileName() const { - return Invocation->getFrontendOpts().Inputs[0].getFile(); + if (Invocation && !Invocation->getFrontendOpts().Inputs.empty()) { + const FrontendInputFile &Input = Invocation->getFrontendOpts().Inputs[0]; + if (Input.isFile()) + return Input.getFile(); + else + return Input.getBuffer()->getBufferIdentifier(); + } + + if (SourceMgr) { + if (const FileEntry * + FE = SourceMgr->getFileEntryForID(SourceMgr->getMainFileID())) + return FE->getName(); + } + + return StringRef(); +} + +StringRef ASTUnit::getASTFileName() const { + if (!isMainFileAST()) + return StringRef(); + + serialization::ModuleFile & + Mod = Reader->getModuleManager().getPrimaryModule(); + return Mod.FileName; } ASTUnit *ASTUnit::create(CompilerInvocation *CI, @@ -1773,7 +1803,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, // Create the target instance. Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), - Clang->getTargetOpts())); + &Clang->getTargetOpts())); if (!Clang->hasTarget()) return 0; @@ -1898,6 +1928,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, AST->IncludeBriefCommentsInCodeCompletion = IncludeBriefCommentsInCodeCompletion; AST->Invocation = CI; + AST->FileSystemOpts = CI->getFileSystemOpts(); + AST->FileMgr = new FileManager(AST->FileSystemOpts); AST->UserFilesAreVolatile = UserFilesAreVolatile; // Recover resources if we crash before exiting this method. @@ -1931,9 +1963,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. - Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(), - ArgEnd - ArgBegin, - ArgBegin); + Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions()); } SmallVector<StoredDiagnostic, 4> StoredDiagnostics; @@ -2369,7 +2399,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, // Create the target instance. Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), - Clang->getTargetOpts())); + &Clang->getTargetOpts())); if (!Clang->hasTarget()) { Clang->setInvocation(0); return; @@ -2434,9 +2464,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. - StoredDiagnostics.insert(StoredDiagnostics.end(), - stored_diag_begin(), - stored_diag_afterDriver_begin()); if (OverrideMainBuffer) { PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); @@ -2458,17 +2485,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, OwningPtr<SyntaxOnlyAction> Act; Act.reset(new SyntaxOnlyAction); if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { - if (OverrideMainBuffer) { - std::string ModName = getPreambleFile(this); - TranslateStoredDiagnostics(Clang->getModuleManager(), ModName, - getSourceManager(), PreambleDiagnostics, - StoredDiagnostics); - } Act->Execute(); Act->EndSourceFile(); } - - checkAndSanitizeDiags(StoredDiagnostics, getSourceManager()); } bool ASTUnit::Save(StringRef File) { diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index 3e66613..3f80a16 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -25,8 +25,8 @@ #include "llvm/ADT/StringMap.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" // FIXME: put this somewhere else? #ifndef S_ISDIR @@ -517,8 +517,8 @@ public: ~StatListener() {} LookupResult getStat(const char *Path, struct stat &StatBuf, - int *FileDescriptor) { - LookupResult Result = statChained(Path, StatBuf, FileDescriptor); + bool isFile, int *FileDescriptor) { + LookupResult Result = statChained(Path, StatBuf, isFile, FileDescriptor); if (Result == CacheMissing) // Failed 'stat'. PM.insert(PTHEntryKeyVariant(Path), PTHEntry()); diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp index 2d58640..a17def0 100644 --- a/lib/Frontend/ChainedIncludesSource.cpp +++ b/lib/Frontend/ChainedIncludesSource.cpp @@ -13,14 +13,14 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/ChainedIncludesSource.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Frontend/CompilerInstance.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/ParseAST.h" #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTWriter.h" -#include "clang/Parse/ParseAST.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/TargetInfo.h" #include "llvm/Support/MemoryBuffer.h" using namespace clang; @@ -39,7 +39,7 @@ 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, SourceLocation(), ASTReader::ARR_None)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. @@ -47,6 +47,7 @@ static ASTReader *createASTReader(CompilerInstance &CI, return Reader.take(); case ASTReader::Failure: + case ASTReader::Missing: case ASTReader::OutOfDate: case ASTReader::VersionMismatch: case ASTReader::ConfigurationMismatch: @@ -99,7 +100,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { Clang->setInvocation(CInvok.take()); Clang->setDiagnostics(Diags.getPtr()); Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), - Clang->getTargetOpts())); + &Clang->getTargetOpts())); Clang->createFileManager(); Clang->createSourceManager(Clang->getFileManager()); Clang->createPreprocessor(); @@ -112,8 +113,6 @@ 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()); @@ -191,7 +190,7 @@ CXXBaseSpecifier * ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) { return getFinalReader().GetExternalCXXBaseSpecifiers(Offset); } -DeclContextLookupResult +bool ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { return getFinalReader().FindExternalVisibleDeclsByName(DC, Name); diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 22a74fc..df06a81 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/CompilerInstance.h" -#include "clang/Sema/Sema.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -17,9 +16,6 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/PTHManager.h" #include "clang/Frontend/ChainedDiagnosticConsumer.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" @@ -27,28 +23,35 @@ #include "clang/Frontend/LogDiagnosticPrinter.h" #include "clang/Frontend/SerializedDiagnosticPrinter.h" #include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Frontend/VerifyDiagnosticConsumer.h" #include "clang/Frontend/Utils.h" -#include "clang/Serialization/ASTReader.h" +#include "clang/Frontend/VerifyDiagnosticConsumer.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/PTHManager.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/CodeCompleteConsumer.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" +#include "clang/Sema/Sema.h" +#include "clang/Serialization/ASTReader.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Support/Timer.h" +#include "llvm/Config/config.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Support/LockFileManager.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -#include "llvm/Support/CrashRecoveryContext.h" -#include "llvm/Config/config.h" +#include <sys/stat.h> +#include <time.h> using namespace clang; CompilerInstance::CompilerInstance() - : Invocation(new CompilerInvocation()), ModuleManager(0) { + : Invocation(new CompilerInvocation()), ModuleManager(0), + BuildGlobalModuleIndex(false), ModuleBuildFailed(false) { } CompilerInstance::~CompilerInstance() { @@ -59,6 +62,13 @@ void CompilerInstance::setInvocation(CompilerInvocation *Value) { Invocation = Value; } +bool CompilerInstance::shouldBuildGlobalModuleIndex() const { + return (BuildGlobalModuleIndex || + (ModuleManager && ModuleManager->isGlobalIndexUnavailable() && + getFrontendOpts().GenerateGlobalModuleIndex)) && + !ModuleBuildFailed; +} + void CompilerInstance::setDiagnostics(DiagnosticsEngine *Value) { Diagnostics = Value; } @@ -92,29 +102,6 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { } // Diagnostics -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)); - if (!ErrorInfo.empty()) { - Diags.Report(diag::err_fe_unable_to_open_logfile) - << DiagOpts->DumpBuildInformation << ErrorInfo; - return; - } - - (*OS) << "clang -cc1 command line arguments: "; - for (unsigned i = 0; i != argc; ++i) - (*OS) << argv[i] << ' '; - (*OS) << '\n'; - - // Chain in a diagnostic client which will log the diagnostics. - DiagnosticConsumer *Logger = - new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true); - Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger)); -} - static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts, const CodeGenOptions *CodeGenOpts, DiagnosticsEngine &Diags) { @@ -128,7 +115,7 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts, ErrorInfo, llvm::raw_fd_ostream::F_Append)); if (!ErrorInfo.empty()) { Diags.Report(diag::warn_fe_cc_log_diagnostics_failure) - << DiagOpts->DumpBuildInformation << ErrorInfo; + << DiagOpts->DiagnosticLogFile << ErrorInfo; } else { FileOS->SetUnbuffered(); FileOS->SetUseAtomicWrites(true); @@ -167,18 +154,16 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts, SerializedConsumer)); } -void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv, - DiagnosticConsumer *Client, +void CompilerInstance::createDiagnostics(DiagnosticConsumer *Client, bool ShouldOwnClient, bool ShouldCloneClient) { - Diagnostics = createDiagnostics(&getDiagnosticOpts(), Argc, Argv, Client, + Diagnostics = createDiagnostics(&getDiagnosticOpts(), Client, ShouldOwnClient, ShouldCloneClient, &getCodeGenOpts()); } IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, - int Argc, const char* const *Argv, DiagnosticConsumer *Client, bool ShouldOwnClient, bool ShouldCloneClient, @@ -205,9 +190,6 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, if (!Opts->DiagnosticLogFile.empty()) SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags); - if (!Opts->DumpBuildInformation.empty()) - SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); - if (!Opts->DiagnosticSerializationFile.empty()) SetupSerializedDiagnostics(Opts, *Diags, Opts->DiagnosticSerializationFile); @@ -260,10 +242,12 @@ void CompilerInstance::createPreprocessor() { } if (PPOpts.DetailedRecord) - PP->createPreprocessingRecord(PPOpts.DetailedRecordConditionalDirectives); + PP->createPreprocessingRecord(); InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts()); + PP->setPreprocessedOutput(getPreprocessorOutputOpts().ShowCPP); + // Set up the module path, including the hash for the // module-creation options. SmallString<256> SpecificModuleCache( @@ -317,7 +301,8 @@ void CompilerInstance::createPCHExternalASTSource(StringRef Path, AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(), DeserializationListener, - Preamble)); + Preamble, + getFrontendOpts().UseGlobalModuleIndex)); ModuleManager = static_cast<ASTReader*>(Source.get()); getASTContext().setExternalSource(Source); } @@ -330,18 +315,21 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path, Preprocessor &PP, ASTContext &Context, void *DeserializationListener, - bool Preamble) { + bool Preamble, + bool UseGlobalModuleIndex) { OwningPtr<ASTReader> Reader; Reader.reset(new ASTReader(PP, Context, Sysroot.empty() ? "" : Sysroot.c_str(), DisablePCHValidation, - AllowPCHWithCompilerErrors)); + AllowPCHWithCompilerErrors, + UseGlobalModuleIndex)); Reader->setDeserializationListener( static_cast<ASTDeserializationListener *>(DeserializationListener)); switch (Reader->ReadAST(Path, Preamble ? serialization::MK_Preamble : serialization::MK_PCH, + SourceLocation(), ASTReader::ARR_None)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. Typically, the @@ -353,6 +341,7 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path, // Unrecoverable failure: don't even try to process the input file. break; + case ASTReader::Missing: case ASTReader::OutOfDate: case ASTReader::VersionMismatch: case ASTReader::ConfigurationMismatch: @@ -619,7 +608,6 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, Diags.Report(diag::err_fe_error_reading) << 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 @@ -631,8 +619,13 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, Diags.Report(diag::err_cannot_open_file) << InputFile << ec.message(); return false; } + + // Create a new virtual file that will have the correct size. + File = FileMgr.getVirtualFile(InputFile, MB->getBufferSize(), 0); SourceMgr.overrideFileContents(File, MB.take()); } + + SourceMgr.createMainFileID(File, Kind); } else { OwningPtr<llvm::MemoryBuffer> SB; if (llvm::MemoryBuffer::getSTDIN(SB)) { @@ -663,7 +656,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { raw_ostream &OS = llvm::errs(); // Create the target instance. - setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); + setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), &getTargetOpts())); if (!hasTarget()) return false; @@ -754,9 +747,27 @@ static void doCompileMapModule(void *UserData) { Data.Instance.ExecuteAction(Data.CreateModuleAction); } +namespace { + /// \brief Function object that checks with the given macro definition should + /// be removed, because it is one of the ignored macros. + class RemoveIgnoredMacro { + const HeaderSearchOptions &HSOpts; + + public: + explicit RemoveIgnoredMacro(const HeaderSearchOptions &HSOpts) + : HSOpts(HSOpts) { } + + bool operator()(const std::pair<std::string, bool> &def) const { + StringRef MacroDef = def.first; + return HSOpts.ModulesIgnoreMacros.count(MacroDef.split('=').first) > 0; + } + }; +} + /// \brief Compile a module file for the given module, using the options /// provided by the importing compiler instance. static void compileModule(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, Module *Module, StringRef ModuleFileName) { llvm::LockFileManager Locked(ModuleFileName); @@ -789,12 +800,25 @@ static void compileModule(CompilerInstance &ImportingInstance, Invocation->getLangOpts()->resetNonModularOptions(); PPOpts.resetNonModularOptions(); + // Remove any macro definitions that are explicitly ignored by the module. + // They aren't supposed to affect how the module is built anyway. + const HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts(); + PPOpts.Macros.erase(std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(), + RemoveIgnoredMacro(HSOpts)), + PPOpts.Macros.end()); + + // Note the name of the module we're building. Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName(); - // Note that this module is part of the module build path, so that we - // can detect cycles in the module graph. - PPOpts.ModuleBuildPath.push_back(Module->getTopLevelModuleName()); + // Make sure that the failed-module structure has been allocated in + // the importing instance, and propagate the pointer to the newly-created + // instance. + PreprocessorOptions &ImportingPPOpts + = ImportingInstance.getInvocation().getPreprocessorOpts(); + if (!ImportingPPOpts.FailedModules) + ImportingPPOpts.FailedModules = new PreprocessorOptions::FailedModulesSet; + PPOpts.FailedModules = ImportingPPOpts.FailedModules; // If there is a module map file, build the module using the module map. // Set up the inputs/outputs so that we build the module from its umbrella @@ -802,6 +826,7 @@ static void compileModule(CompilerInstance &ImportingInstance, FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); FrontendOpts.OutputFile = ModuleFileName.str(); FrontendOpts.DisableFree = false; + FrontendOpts.GenerateGlobalModuleIndex = false; FrontendOpts.Inputs.clear(); InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts()); @@ -843,11 +868,21 @@ static void compileModule(CompilerInstance &ImportingInstance, // module. CompilerInstance Instance; Instance.setInvocation(&*Invocation); - Instance.createDiagnostics(/*argc=*/0, /*argv=*/0, - &ImportingInstance.getDiagnosticClient(), + Instance.createDiagnostics(&ImportingInstance.getDiagnosticClient(), /*ShouldOwnClient=*/true, /*ShouldCloneClient=*/true); - + + // Note that this module is part of the module build stack, so that we + // can detect cycles in the module graph. + Instance.createFileManager(); // FIXME: Adopt file manager from importer? + Instance.createSourceManager(Instance.getFileManager()); + SourceManager &SourceMgr = Instance.getSourceManager(); + SourceMgr.setModuleBuildStack( + ImportingInstance.getSourceManager().getModuleBuildStack()); + SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(), + FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager())); + + // Construct a module-generating action. GenerateModuleAction CreateModuleAction; @@ -865,19 +900,204 @@ static void compileModule(CompilerInstance &ImportingInstance, Instance.clearOutputFiles(/*EraseFiles=*/true); if (!TempModuleMapFileName.empty()) llvm::sys::Path(TempModuleMapFileName).eraseFromDisk(); + + // We've rebuilt a module. If we're allowed to generate or update the global + // module index, record that fact in the importing compiler instance. + if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) { + ImportingInstance.setBuildGlobalModuleIndex(true); + } +} + +/// \brief Diagnose differences between the current definition of the given +/// configuration macro and the definition provided on the command line. +static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro, + Module *Mod, SourceLocation ImportLoc) { + IdentifierInfo *Id = PP.getIdentifierInfo(ConfigMacro); + SourceManager &SourceMgr = PP.getSourceManager(); + + // If this identifier has never had a macro definition, then it could + // not have changed. + if (!Id->hadMacroDefinition()) + return; + + // If this identifier does not currently have a macro definition, + // check whether it had one on the command line. + if (!Id->hasMacroDefinition()) { + MacroDirective::DefInfo LatestDef = + PP.getMacroDirectiveHistory(Id)->getDefinition(); + for (MacroDirective::DefInfo Def = LatestDef; Def; + Def = Def.getPreviousDefinition()) { + FileID FID = SourceMgr.getFileID(Def.getLocation()); + if (FID.isInvalid()) + continue; + + // We only care about the predefines buffer. + if (FID != PP.getPredefinesFileID()) + continue; + + // This macro was defined on the command line, then #undef'd later. + // Complain. + PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) + << true << ConfigMacro << Mod->getFullModuleName(); + if (LatestDef.isUndefined()) + PP.Diag(LatestDef.getUndefLocation(), diag::note_module_def_undef_here) + << true; + return; + } + + // Okay: no definition in the predefines buffer. + return; + } + + // This identifier has a macro definition. Check whether we had a definition + // on the command line. + MacroDirective::DefInfo LatestDef = + PP.getMacroDirectiveHistory(Id)->getDefinition(); + MacroDirective::DefInfo PredefinedDef; + for (MacroDirective::DefInfo Def = LatestDef; Def; + Def = Def.getPreviousDefinition()) { + FileID FID = SourceMgr.getFileID(Def.getLocation()); + if (FID.isInvalid()) + continue; + + // We only care about the predefines buffer. + if (FID != PP.getPredefinesFileID()) + continue; + + PredefinedDef = Def; + break; + } + + // If there was no definition for this macro in the predefines buffer, + // complain. + if (!PredefinedDef || + (!PredefinedDef.getLocation().isValid() && + PredefinedDef.getUndefLocation().isValid())) { + PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) + << false << ConfigMacro << Mod->getFullModuleName(); + PP.Diag(LatestDef.getLocation(), diag::note_module_def_undef_here) + << false; + return; + } + + // If the current macro definition is the same as the predefined macro + // definition, it's okay. + if (LatestDef.getMacroInfo() == PredefinedDef.getMacroInfo() || + LatestDef.getMacroInfo()->isIdenticalTo(*PredefinedDef.getMacroInfo(),PP, + /*Syntactically=*/true)) + return; + + // The macro definitions differ. + PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) + << false << ConfigMacro << Mod->getFullModuleName(); + PP.Diag(LatestDef.getLocation(), diag::note_module_def_undef_here) + << false; +} + +/// \brief Write a new timestamp file with the given path. +static void writeTimestampFile(StringRef TimestampFile) { + std::string ErrorInfo; + llvm::raw_fd_ostream Out(TimestampFile.str().c_str(), ErrorInfo, + llvm::raw_fd_ostream::F_Binary); } -Module *CompilerInstance::loadModule(SourceLocation ImportLoc, - ModuleIdPath Path, - Module::NameVisibilityKind Visibility, - bool IsInclusionDirective) { +/// \brief Prune the module cache of modules that haven't been accessed in +/// a long time. +static void pruneModuleCache(const HeaderSearchOptions &HSOpts) { + struct stat StatBuf; + llvm::SmallString<128> TimestampFile; + TimestampFile = HSOpts.ModuleCachePath; + llvm::sys::path::append(TimestampFile, "modules.timestamp"); + + // Try to stat() the timestamp file. + if (::stat(TimestampFile.c_str(), &StatBuf)) { + // If the timestamp file wasn't there, create one now. + if (errno == ENOENT) { + writeTimestampFile(TimestampFile); + } + return; + } + + // Check whether the time stamp is older than our pruning interval. + // If not, do nothing. + time_t TimeStampModTime = StatBuf.st_mtime; + time_t CurrentTime = time(0); + if (CurrentTime - TimeStampModTime <= time_t(HSOpts.ModuleCachePruneInterval)) + return; + + // Write a new timestamp file so that nobody else attempts to prune. + // There is a benign race condition here, if two Clang instances happen to + // notice at the same time that the timestamp is out-of-date. + writeTimestampFile(TimestampFile); + + // Walk the entire module cache, looking for unused module files and module + // indices. + llvm::error_code EC; + SmallString<128> ModuleCachePathNative; + llvm::sys::path::native(HSOpts.ModuleCachePath, ModuleCachePathNative); + for (llvm::sys::fs::directory_iterator + Dir(ModuleCachePathNative.str(), EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + // If we don't have a directory, there's nothing to look into. + bool IsDirectory; + if (llvm::sys::fs::is_directory(Dir->path(), IsDirectory) || !IsDirectory) + continue; + + // Walk all of the files within this directory. + bool RemovedAllFiles = true; + for (llvm::sys::fs::directory_iterator File(Dir->path(), EC), FileEnd; + File != FileEnd && !EC; File.increment(EC)) { + // We only care about module and global module index files. + if (llvm::sys::path::extension(File->path()) != ".pcm" && + llvm::sys::path::filename(File->path()) != "modules.idx") { + RemovedAllFiles = false; + continue; + } + + // Look at this file. If we can't stat it, there's nothing interesting + // there. + if (::stat(File->path().c_str(), &StatBuf)) { + RemovedAllFiles = false; + continue; + } + + // If the file has been used recently enough, leave it there. + time_t FileAccessTime = StatBuf.st_atime; + if (CurrentTime - FileAccessTime <= + time_t(HSOpts.ModuleCachePruneAfter)) { + RemovedAllFiles = false; + continue; + } + + // Remove the file. + bool Existed; + if (llvm::sys::fs::remove(File->path(), Existed) || !Existed) { + RemovedAllFiles = false; + } + } + + // If we removed all of the files in the directory, remove the directory + // itself. + if (RemovedAllFiles) { + bool Existed; + llvm::sys::fs::remove(Dir->path(), Existed); + } + } +} + +ModuleLoadResult +CompilerInstance::loadModule(SourceLocation ImportLoc, + ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) { // If we've already handled this import, just return the cached result. // This one-element cache is important to eliminate redundant diagnostics // when both the preprocessor and parser see the same import declaration. if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc) { // Make the named module visible. if (LastModuleImportResult) - ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility); + ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility, + ImportLoc, /*Complain=*/false); return LastModuleImportResult; } @@ -901,79 +1121,36 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, // Search for a module with the given name. Module = PP->getHeaderSearchInfo().lookupModule(ModuleName); std::string ModuleFileName; - if (Module) + if (Module) { ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module); - else + } else ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(ModuleName); - - if (ModuleFileName.empty()) { - getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) - << ModuleName - << SourceRange(ImportLoc, ModuleNameLoc); - LastModuleImportLoc = ImportLoc; - LastModuleImportResult = 0; - return 0; - } - - const FileEntry *ModuleFile - = getFileManager().getFile(ModuleFileName, /*OpenFile=*/false, - /*CacheFailure=*/false); - bool BuildingModule = false; - if (!ModuleFile && Module) { - // The module is not cached, but we have a module map from which we can - // build the module. - - // Check whether there is a cycle in the module graph. - SmallVectorImpl<std::string> &ModuleBuildPath - = getPreprocessorOpts().ModuleBuildPath; - SmallVectorImpl<std::string>::iterator Pos - = std::find(ModuleBuildPath.begin(), ModuleBuildPath.end(), ModuleName); - if (Pos != ModuleBuildPath.end()) { - SmallString<256> CyclePath; - for (; Pos != ModuleBuildPath.end(); ++Pos) { - CyclePath += *Pos; - CyclePath += " -> "; - } - CyclePath += ModuleName; - - getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle) - << ModuleName << CyclePath; - return 0; - } - - getDiagnostics().Report(ModuleNameLoc, diag::warn_module_build) - << ModuleName; - BuildingModule = true; - compileModule(*this, Module, ModuleFileName); - ModuleFile = FileMgr->getFile(ModuleFileName); - } - - if (!ModuleFile) { - getDiagnostics().Report(ModuleNameLoc, - BuildingModule? diag::err_module_not_built - : diag::err_module_not_found) - << ModuleName - << SourceRange(ImportLoc, ModuleNameLoc); - return 0; - } // If we don't already have an ASTReader, create one now. if (!ModuleManager) { if (!hasASTContext()) createASTContext(); + // If we're not recursively building a module, check whether we + // need to prune the module cache. + if (getSourceManager().getModuleBuildStack().empty() && + getHeaderSearchOpts().ModuleCachePruneInterval > 0 && + getHeaderSearchOpts().ModuleCachePruneAfter > 0) { + pruneModuleCache(getHeaderSearchOpts()); + } + std::string Sysroot = getHeaderSearchOpts().Sysroot; const PreprocessorOptions &PPOpts = getPreprocessorOpts(); ModuleManager = new ASTReader(getPreprocessor(), *Context, Sysroot.empty() ? "" : Sysroot.c_str(), - PPOpts.DisablePCHValidation); + PPOpts.DisablePCHValidation, + /*AllowASTWithCompilerErrors=*/false, + getFrontendOpts().UseGlobalModuleIndex); if (hasASTConsumer()) { ModuleManager->setDeserializationListener( getASTConsumer().GetASTDeserializationListener()); getASTContext().setASTMutationListener( getASTConsumer().GetASTMutationListener()); - getPreprocessor().setPPMutationListener( - getASTConsumer().GetPPMutationListener()); } OwningPtr<ExternalASTSource> Source; Source.reset(ModuleManager); @@ -984,31 +1161,87 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, ModuleManager->StartTranslationUnit(&getASTConsumer()); } - // 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, - ARRFlags)) { + // Try to load the module file. + unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing; + switch (ModuleManager->ReadAST(ModuleFileName, serialization::MK_Module, + ImportLoc, ARRFlags)) { case ASTReader::Success: break; case ASTReader::OutOfDate: { - // The module file is out-of-date. Rebuild it. - getFileManager().invalidateCache(ModuleFile); + // The module file is out-of-date. Remove it, then rebuild it. 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) { + } + // Fall through to build the module again. + + case ASTReader::Missing: { + // The module file is (now) missing. Build it. + + // If we don't have a module, we don't know how to build the module file. + // Complain and return. + if (!Module) { + getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) + << ModuleName + << SourceRange(ImportLoc, ModuleNameLoc); + ModuleBuildFailed = true; + return ModuleLoadResult(); + } + + // Check whether there is a cycle in the module graph. + ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack(); + ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end(); + for (; Pos != PosEnd; ++Pos) { + if (Pos->first == ModuleName) + break; + } + + if (Pos != PosEnd) { + SmallString<256> CyclePath; + for (; Pos != PosEnd; ++Pos) { + CyclePath += Pos->first; + CyclePath += " -> "; + } + CyclePath += ModuleName; + + getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle) + << ModuleName << CyclePath; + return ModuleLoadResult(); + } + + // Check whether we have already attempted to build this module (but + // failed). + if (getPreprocessorOpts().FailedModules && + getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) { + getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built) + << ModuleName + << SourceRange(ImportLoc, ModuleNameLoc); + ModuleBuildFailed = true; + return ModuleLoadResult(); + } + + // Try to compile the module. + compileModule(*this, ModuleNameLoc, Module, ModuleFileName); + + // Try to read the module file, now that we've compiled it. + ASTReader::ASTReadResult ReadResult + = ModuleManager->ReadAST(ModuleFileName, + serialization::MK_Module, ImportLoc, + ASTReader::ARR_Missing); + if (ReadResult != ASTReader::Success) { + if (ReadResult == ASTReader::Missing) { + getDiagnostics().Report(ModuleNameLoc, + Module? diag::err_module_not_built + : diag::err_module_not_found) + << ModuleName + << SourceRange(ImportLoc, ModuleNameLoc); + } + + if (getPreprocessorOpts().FailedModules) + getPreprocessorOpts().FailedModules->addFailed(ModuleName); KnownModules[Path[0].first] = 0; - return 0; + ModuleBuildFailed = true; + return ModuleLoadResult(); } // Okay, we've rebuilt and now loaded the module. @@ -1021,12 +1254,13 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, // FIXME: The ASTReader will already have complained, but can we showhorn // that diagnostic information into a more useful form? KnownModules[Path[0].first] = 0; - return 0; + return ModuleLoadResult(); case ASTReader::Failure: // Already complained, but note now that we failed. KnownModules[Path[0].first] = 0; - return 0; + ModuleBuildFailed = true; + return ModuleLoadResult(); } if (!Module) { @@ -1036,16 +1270,13 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, .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; } // If we never found the module, fail. if (!Module) - return 0; + return ModuleLoadResult(); // Verify that the rest of the module path actually corresponds to // a submodule. @@ -1056,7 +1287,7 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, if (!Sub) { // Attempt to perform typo correction to find a module name that works. - llvm::SmallVector<StringRef, 2> Best; + SmallVector<StringRef, 2> Best; unsigned BestEditDistance = (std::numeric_limits<unsigned>::max)(); for (clang::Module::submodule_iterator J = Module->submodule_begin(), @@ -1115,7 +1346,7 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, << Module->getFullModuleName() << SourceRange(Path.front().second, Path.back().second); - return 0; + return ModuleLoadResult(0, true); } // Check whether this module is available. @@ -1126,13 +1357,21 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, << Feature << SourceRange(Path.front().second, Path.back().second); LastModuleImportLoc = ImportLoc; - LastModuleImportResult = 0; - return 0; + LastModuleImportResult = ModuleLoadResult(); + return ModuleLoadResult(); } - ModuleManager->makeModuleVisible(Module, Visibility); + ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc, + /*Complain=*/true); } - + + // Check for any configuration macros that have changed. + clang::Module *TopModule = Module->getTopLevelModule(); + for (unsigned I = 0, N = TopModule->ConfigMacros.size(); I != N; ++I) { + checkConfigMacro(getPreprocessor(), TopModule->ConfigMacros[I], + Module, ImportLoc); + } + // If this module import was due to an inclusion directive, create an // implicit import declaration to capture it in the AST. if (IsInclusionDirective && hasASTContext()) { @@ -1146,6 +1385,14 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, } LastModuleImportLoc = ImportLoc; - LastModuleImportResult = Module; - return Module; + LastModuleImportResult = ModuleLoadResult(Module, false); + return LastModuleImportResult; +} + +void CompilerInstance::makeModuleVisible(Module *Mod, + Module::NameVisibilityKind Visibility, + SourceLocation ImportLoc, + bool Complain){ + ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc, Complain); } + diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index b9c198b..41f9417 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -9,17 +9,16 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Basic/Diagnostic.h" -#include "clang/Basic/Version.h" #include "clang/Basic/FileManager.h" -#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Basic/Version.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" -#include "clang/Driver/Options.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" -#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Driver/Options.h" #include "clang/Frontend/LangStandard.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "clang/Serialization/ASTReader.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/OwningPtr.h" @@ -71,7 +70,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, assert (A->getOption().matches(options::OPT_O)); - llvm::StringRef S(A->getValue()); + StringRef S(A->getValue()); if (S == "s" || S == "z" || S.empty()) return 2; @@ -189,22 +188,6 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } } - if (Arg *A = Args.getLastArg(OPT_analyzer_ipa)) { - StringRef Name = A->getValue(); - AnalysisIPAMode Value = llvm::StringSwitch<AnalysisIPAMode>(Name) -#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \ - .Case(CMDFLAG, NAME) -#include "clang/StaticAnalyzer/Core/Analyses.def" - .Default(NumIPAModes); - if (Value == NumIPAModes) { - Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << Name; - Success = false; - } else { - Opts.IPAMode = Value; - } - } - if (Arg *A = Args.getLastArg(OPT_analyzer_inlining_mode)) { StringRef Name = A->getValue(); AnalysisInliningMode Value = llvm::StringSwitch<AnalysisInliningMode>(Name) @@ -235,15 +218,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function); Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG); Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); - Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); 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, Opts.InlineMaxStackDepth, Diags); - Opts.InlineMaxFunctionSize = - Args.getLastArgIntValue(OPT_analyzer_inline_max_function_size, - Opts.InlineMaxFunctionSize, Diags); Opts.CheckersControlList.clear(); for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker, @@ -300,6 +279,10 @@ static bool ParseMigratorArgs(MigratorOptions &Opts, ArgList &Args) { return true; } +static void ParseCommentArgs(CommentOptions &Opts, ArgList &Args) { + Opts.BlockCommandNames = Args.getAllArgValues(OPT_fcomment_block_commands); +} + static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { using namespace options; @@ -332,13 +315,16 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.setDebugInfo(CodeGenOptions::FullDebugInfo); } Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); + Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); + Opts.ModulesAutolink = Args.hasArg(OPT_fmodules_autolink); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables); Opts.UseRegisterSizedBitfieldAccess = Args.hasArg( OPT_fuse_register_sized_bitfield_access); Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing); + Opts.StructPathTBAA = Args.hasArg(OPT_struct_path_tbaa); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); @@ -373,6 +359,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags); Opts.NoGlobalMerge = Args.hasArg(OPT_mno_global_merge); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); + Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks); Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer); Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels); @@ -386,8 +373,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ); - Opts.BoundsChecking = Args.getLastArgIntValue(OPT_fbounds_checking_EQ, 0, - Diags); Opts.UseInitArray = Args.hasArg(OPT_fuse_init_array); Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections); @@ -395,15 +380,40 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); + Opts.SanitizeRecover = !Args.hasArg(OPT_fno_sanitize_recover); - Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); - Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); + Opts.DisableGCov = Args.hasArg(OPT_test_coverage); 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); + if (Opts.EmitGcovArcs || Opts.EmitGcovNotes) { Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file); + Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum); + Opts.CoverageNoFunctionNamesInData = + Args.hasArg(OPT_coverage_no_function_names_in_data); + if (Args.hasArg(OPT_coverage_version_EQ)) { + StringRef CoverageVersion = Args.getLastArgValue(OPT_coverage_version_EQ); + if (CoverageVersion.size() != 4) { + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_coverage_version_EQ)->getAsString(Args) + << CoverageVersion; + } else { + memcpy(Opts.CoverageVersion, CoverageVersion.data(), 4); + } + } + } + + Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); + Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); + Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file); + Opts.SanitizerBlacklistFile = Args.getLastArgValue(OPT_fsanitize_blacklist); + Opts.SanitizeMemoryTrackOrigins = + Args.hasArg(OPT_fsanitize_memory_track_origins); + Opts.SanitizeAddressZeroBaseShadow = + Args.hasArg(OPT_fsanitize_address_zero_base_shadow); + Opts.SanitizeUndefinedTrapOnError = + Args.hasArg(OPT_fsanitize_undefined_trap_on_error); Opts.SSPBufferSize = Args.getLastArgIntValue(OPT_stack_protector_buffer_size, 8, Diags); Opts.StackRealignment = Args.hasArg(OPT_mstackrealign); @@ -446,6 +456,18 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } } + if (Arg *A = Args.getLastArg(OPT_ffp_contract)) { + StringRef Val = A->getValue(); + if (Val == "fast") + Opts.setFPContractMode(CodeGenOptions::FPC_Fast); + else if (Val == "on") + Opts.setFPContractMode(CodeGenOptions::FPC_On); + else if (Val == "off") + Opts.setFPContractMode(CodeGenOptions::FPC_Off); + else + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; + } + return Success; } @@ -538,9 +560,11 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); + Opts.ShowPresumedLoc = !Args.hasArg(OPT_fno_diagnostics_use_presumed_location); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); Opts.ElideType = !Args.hasArg(OPT_fno_elide_type); Opts.ShowTemplateTree = Args.hasArg(OPT_fdiagnostics_show_template_tree); + Opts.WarnOnSpellCheck = Args.hasArg(OPT_fwarn_on_spellcheck); Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags); Opts.MacroBacktraceLimit = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit, @@ -562,7 +586,6 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, << Opts.TabStop << DiagnosticOptions::DefaultTabStop; } Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags); - Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information); addWarningArgs(Args, Opts.Warnings); return Success; @@ -623,6 +646,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::InitOnly; break; case OPT_fsyntax_only: Opts.ProgramAction = frontend::ParseSyntaxOnly; break; + case OPT_module_file_info: + Opts.ProgramAction = frontend::ModuleFileInfo; break; case OPT_print_decl_contexts: Opts.ProgramAction = frontend::PrintDeclContext; break; case OPT_print_preamble: @@ -689,7 +714,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile); Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp); Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter); - + Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index); + Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex; + Opts.CodeCompleteOpts.IncludeMacros = Args.hasArg(OPT_code_completion_macros); Opts.CodeCompleteOpts.IncludeCodePatterns @@ -756,7 +783,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("objective-c-header", IK_ObjC) .Case("c++-header", IK_CXX) .Case("objective-c++-header", IK_ObjCXX) - .Case("ast", IK_AST) + .Cases("ast", "pcm", IK_AST) .Case("ir", IK_LLVM_IR) .Default(IK_None); if (DashX == IK_None) @@ -811,9 +838,18 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ)) Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0); Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); - Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path); + Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodules_cache_path); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); - + Opts.ModuleCachePruneInterval + = Args.getLastArgIntValue(OPT_fmodules_prune_interval, 7*24*60*60); + Opts.ModuleCachePruneAfter + = Args.getLastArgIntValue(OPT_fmodules_prune_after, 31*24*60*60); + for (arg_iterator it = Args.filtered_begin(OPT_fmodules_ignore_macro), + ie = Args.filtered_end(); it != ie; ++it) { + StringRef MacroDef = (*it)->getValue(); + Opts.ModulesIgnoreMacros.insert(MacroDef.split('=').first); + } + // Add -I..., -F..., and -index-header-map options in order. bool IsIndexHeaderMap = false; for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F, @@ -828,12 +864,12 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { frontend::IncludeDirGroup Group = IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled; - Opts.AddPath((*it)->getValue(), Group, true, - /*IsFramework=*/ (*it)->getOption().matches(OPT_F), false); + Opts.AddPath((*it)->getValue(), Group, + /*IsFramework=*/ (*it)->getOption().matches(OPT_F), true); IsIndexHeaderMap = false; } - // Add -iprefix/-iwith-prefix/-iwithprefixbefore options. + // Add -iprefix/-iwithprefix/-iwithprefixbefore options. StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix, OPT_iwithprefixbefore), @@ -843,50 +879,50 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Prefix = A->getValue(); else if (A->getOption().matches(OPT_iwithprefix)) Opts.AddPath(Prefix.str() + A->getValue(), - frontend::System, false, false, false); + frontend::After, false, true); else Opts.AddPath(Prefix.str() + A->getValue(), - frontend::Angled, false, false, false); + frontend::Angled, false, true); } for (arg_iterator it = Args.filtered_begin(OPT_idirafter), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(), frontend::After, true, false, false); + Opts.AddPath((*it)->getValue(), frontend::After, false, true); for (arg_iterator it = Args.filtered_begin(OPT_iquote), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(), frontend::Quoted, true, false, false); + Opts.AddPath((*it)->getValue(), frontend::Quoted, false, true); for (arg_iterator it = Args.filtered_begin(OPT_isystem, OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(), frontend::System, true, false, + Opts.AddPath((*it)->getValue(), frontend::System, 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(), frontend::System, true, true, - true); + Opts.AddPath((*it)->getValue(), frontend::System, 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(), frontend::CSystem, true, false, true); + Opts.AddPath((*it)->getValue(), frontend::CSystem, false, true); for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(), frontend::CXXSystem, true, false, true); + Opts.AddPath((*it)->getValue(), frontend::CXXSystem, false, true); for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(), frontend::ObjCSystem, true, false,true); + Opts.AddPath((*it)->getValue(), frontend::ObjCSystem, false,true); for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(), frontend::ObjCXXSystem, true, false, - true); + Opts.AddPath((*it)->getValue(), frontend::ObjCXXSystem, false, true); // Add the internal paths from a driver that detects standard include paths. for (arg_iterator I = Args.filtered_begin(OPT_internal_isystem, OPT_internal_externc_isystem), E = Args.filtered_end(); - I != E; ++I) - Opts.AddPath((*I)->getValue(), frontend::System, - false, false, /*IgnoreSysRoot=*/true, /*IsInternal=*/true, - (*I)->getOption().matches(OPT_internal_externc_isystem)); + I != E; ++I) { + frontend::IncludeDirGroup Group = frontend::System; + if ((*I)->getOption().matches(OPT_internal_externc_isystem)) + Group = frontend::ExternCSystem; + Opts.AddPath((*I)->getValue(), Group, false, true); + } // Add the path prefixes which are implicitly treated as being system headers. for (arg_iterator I = Args.filtered_begin(OPT_isystem_prefix, @@ -945,7 +981,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.C99 = Std.isC99(); Opts.C11 = Std.isC11(); Opts.CPlusPlus = Std.isCPlusPlus(); - Opts.CPlusPlus0x = Std.isCPlusPlus0x(); + Opts.CPlusPlus11 = Std.isCPlusPlus11(); Opts.CPlusPlus1y = Std.isCPlusPlus1y(); Opts.Digraphs = Std.hasDigraphs(); Opts.GNUMode = Std.isGNUMode(); @@ -973,6 +1009,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.CXXOperatorNames = 1; Opts.LaxVectorConversions = 0; Opts.DefaultFPContract = 1; + Opts.NativeHalfType = 1; } if (LangStd == LangStandard::lang_cuda) @@ -994,6 +1031,24 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.DollarIdents = !Opts.AsmPreprocessor; } +/// Attempt to parse a visibility value out of the given argument. +static Visibility parseVisibility(Arg *arg, ArgList &args, + DiagnosticsEngine &diags) { + StringRef value = arg->getValue(); + if (value == "default") { + return DefaultVisibility; + } else if (value == "hidden") { + return HiddenVisibility; + } else if (value == "protected") { + // FIXME: diagnose if target does not support protected visibility + return ProtectedVisibility; + } + + diags.Report(diag::err_drv_invalid_value) + << arg->getAsString(args) << value; + return DefaultVisibility; +} + static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { // FIXME: Cleanup per-file based stuff. @@ -1122,31 +1177,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_pthread)) Opts.POSIXThreads = 1; - if (Args.hasArg(OPT_fdelayed_template_parsing)) - Opts.DelayedTemplateParsing = 1; - - StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); - if (Vis == "default") - Opts.setVisibilityMode(DefaultVisibility); - else if (Vis == "hidden") - Opts.setVisibilityMode(HiddenVisibility); - else if (Vis == "protected") - // FIXME: diagnose if target does not support protected visibility - Opts.setVisibilityMode(ProtectedVisibility); - else - Diags.Report(diag::err_drv_invalid_value) - << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; + // The value-visibility mode defaults to "default". + if (Arg *visOpt = Args.getLastArg(OPT_fvisibility)) { + Opts.setValueVisibilityMode(parseVisibility(visOpt, Args, Diags)); + } else { + Opts.setValueVisibilityMode(DefaultVisibility); + } - if (Arg *A = Args.getLastArg(OPT_ffp_contract)) { - StringRef Val = A->getValue(); - if (Val == "fast") - Opts.setFPContractMode(LangOptions::FPC_Fast); - else if (Val == "on") - Opts.setFPContractMode(LangOptions::FPC_On); - else if (Val == "off") - Opts.setFPContractMode(LangOptions::FPC_Off); - else - Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; + // The type-visibility mode defaults to the value-visibility mode. + if (Arg *typeVisOpt = Args.getLastArg(OPT_ftype_visibility)) { + Opts.setTypeVisibilityMode(parseVisibility(typeVisOpt, Args, Diags)); + } else { + Opts.setTypeVisibilityMode(Opts.getValueVisibilityMode()); } if (Args.hasArg(OPT_fvisibility_inlines_hidden)) @@ -1171,6 +1213,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.MicrosoftExt = Args.hasArg(OPT_fms_extensions) || Args.hasArg(OPT_fms_compatibility); Opts.MicrosoftMode = Args.hasArg(OPT_fms_compatibility); + Opts.AsmBlocks = Args.hasArg(OPT_fasm_blocks) || Opts.MicrosoftExt; Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags); Opts.Borland = Args.hasArg(OPT_fborland_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); @@ -1205,6 +1248,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Diags); Opts.ConstexprCallDepth = Args.getLastArgIntValue(OPT_fconstexpr_depth, 512, Diags); + Opts.BracketDepth = Args.getLastArgIntValue(OPT_fbracket_depth, 256, Diags); Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing); Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy_EQ, 0, Diags); @@ -1238,6 +1282,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack); Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name); + // Check if -fopenmp is specified. + Opts.OpenMP = Args.hasArg(OPT_fopenmp); + // Record whether the __DEPRECATED define was requested. Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro, OPT_fno_deprecated_macro, @@ -1257,8 +1304,6 @@ 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); @@ -1293,7 +1338,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, .Default(Unknown)) { #define SANITIZER(NAME, ID) \ case ID: \ - Opts.Sanitize##ID = true; \ + Opts.Sanitize.ID = true; \ break; #include "clang/Basic/Sanitizers.def" @@ -1354,8 +1399,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros); // Add the ordered list of -includes. - for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch, - OPT_include_pth), + for (arg_iterator it = Args.filtered_begin(OPT_include), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; Opts.Includes.push_back(A->getValue()); @@ -1400,9 +1444,49 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, } static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, - ArgList &Args) { + ArgList &Args, + frontend::ActionKind Action) { using namespace options; - Opts.ShowCPP = !Args.hasArg(OPT_dM); + + switch (Action) { + case frontend::ASTDeclList: + case frontend::ASTDump: + case frontend::ASTDumpXML: + case frontend::ASTPrint: + case frontend::ASTView: + case frontend::EmitAssembly: + case frontend::EmitBC: + case frontend::EmitHTML: + case frontend::EmitLLVM: + case frontend::EmitLLVMOnly: + case frontend::EmitCodeGenOnly: + case frontend::EmitObj: + case frontend::FixIt: + case frontend::GenerateModule: + case frontend::GeneratePCH: + case frontend::GeneratePTH: + case frontend::ParseSyntaxOnly: + case frontend::ModuleFileInfo: + case frontend::PluginAction: + case frontend::PrintDeclContext: + case frontend::RewriteObjC: + case frontend::RewriteTest: + case frontend::RunAnalysis: + case frontend::MigrateSource: + Opts.ShowCPP = 0; + break; + + case frontend::DumpRawTokens: + case frontend::DumpTokens: + case frontend::InitOnly: + case frontend::PrintPreamble: + case frontend::PrintPreprocessedInput: + case frontend::RewriteMacros: + case frontend::RunPreprocessorOnly: + Opts.ShowCPP = !Args.hasArg(OPT_dM); + break; + } + Opts.ShowComments = Args.hasArg(OPT_C); Opts.ShowLineMarkers = !Args.hasArg(OPT_P); Opts.ShowMacroComments = Args.hasArg(OPT_CC); @@ -1466,6 +1550,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, &Diags) && Success; + ParseCommentArgs(Res.getLangOpts()->CommentOpts, *Args); ParseFileSystemArgs(Res.getFileSystemOpts(), *Args); // FIXME: We shouldn't have to pass the DashX option around here InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); @@ -1483,7 +1568,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, // parameters from the function and the "FileManager.h" #include. FileManager FileMgr(Res.getFileSystemOpts()); ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags); - ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); + ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args, + Res.getFrontendOpts().ProgramAction); ParseTargetArgs(Res.getTargetOpts(), *Args); return Success; @@ -1492,7 +1578,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, namespace { class ModuleSignature { - llvm::SmallVector<uint64_t, 16> Data; + SmallVector<uint64_t, 16> Data; unsigned CurBit; uint64_t CurValue; @@ -1543,6 +1629,8 @@ llvm::APInt ModuleSignature::getAsInteger() const { } std::string CompilerInvocation::getModuleHash() const { + // Note: For QoI reasons, the things we use as a hash here should all be + // dumped via the -module-info flag. using llvm::hash_code; using llvm::hash_value; using llvm::hash_combine; @@ -1570,6 +1658,7 @@ std::string CompilerInvocation::getModuleHash() const { // Extend the signature with preprocessor options. const PreprocessorOptions &ppOpts = getPreprocessorOpts(); + const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord); std::vector<StringRef> MacroDefs; @@ -1577,11 +1666,19 @@ std::string CompilerInvocation::getModuleHash() const { I = getPreprocessorOpts().Macros.begin(), IEnd = getPreprocessorOpts().Macros.end(); I != IEnd; ++I) { + // If we're supposed to ignore this macro for the purposes of modules, + // don't put it into the hash. + if (!hsOpts.ModulesIgnoreMacros.empty()) { + // Check whether we're ignoring this macro. + StringRef MacroDef = I->first; + if (hsOpts.ModulesIgnoreMacros.count(MacroDef.split('=').first)) + continue; + } + code = hash_combine(code, I->first, I->second); } // Extend the signature with the sysroot. - const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes, hsOpts.UseStandardSystemIncludes, hsOpts.UseStandardCXXIncludes, diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp index d82cb6d..e25eb43 100644 --- a/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -11,15 +11,15 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/DiagnosticOptions.h" #include "clang/Frontend/Utils.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Driver/ArgList.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" -#include "clang/Driver/ArgList.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Support/Host.h" using namespace clang; @@ -34,9 +34,7 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList, if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. - Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions, - ArgList.size(), - ArgList.begin()); + Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions); } SmallVector<const char *, 16> Args; @@ -48,7 +46,7 @@ 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); + "a.out", *Diags); // 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 53ea8be..628def6 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -151,12 +151,14 @@ void DependencyFileCallback::AddFilename(StringRef Filename) { Files.push_back(Filename); } -/// PrintFilename - GCC escapes spaces, but apparently not ' or " or other -/// scary characters. +/// PrintFilename - GCC escapes spaces, # and $, but apparently not ' or " or +/// other scary characters. static void PrintFilename(raw_ostream &OS, StringRef Filename) { for (unsigned i = 0, e = Filename.size(); i != e; ++i) { - if (Filename[i] == ' ') + if (Filename[i] == ' ' || Filename[i] == '#') OS << '\\'; + else if (Filename[i] == '$') // $ is escaped by $$. + OS << '$'; OS << Filename[i]; } } diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp index 28d9c5d..e128d91 100644 --- a/lib/Frontend/DependencyGraph.cpp +++ b/lib/Frontend/DependencyGraph.cpp @@ -19,8 +19,8 @@ #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SetVector.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/GraphWriter.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; namespace DOT = llvm::DOT; @@ -31,15 +31,14 @@ class DependencyGraphCallback : public PPCallbacks { std::string OutputFile; std::string SysRoot; llvm::SetVector<const FileEntry *> AllFiles; - typedef llvm::DenseMap<const FileEntry *, - llvm::SmallVector<const FileEntry *, 2> > - DependencyMap; + typedef llvm::DenseMap<const FileEntry *, + SmallVector<const FileEntry *, 2> > DependencyMap; DependencyMap Dependencies; private: - llvm::raw_ostream &writeNodeReference(llvm::raw_ostream &OS, - const FileEntry *Node); + raw_ostream &writeNodeReference(raw_ostream &OS, + const FileEntry *Node); void OutputGraphFile(); public: @@ -93,8 +92,8 @@ void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc, AllFiles.insert(FromFile); } -llvm::raw_ostream & -DependencyGraphCallback::writeNodeReference(llvm::raw_ostream &OS, +raw_ostream & +DependencyGraphCallback::writeNodeReference(raw_ostream &OS, const FileEntry *Node) { OS << "header_" << Node->getUID(); return OS; diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp index 359b82b..3b4f55c 100644 --- a/lib/Frontend/DiagnosticRenderer.cpp +++ b/lib/Frontend/DiagnosticRenderer.cpp @@ -11,15 +11,15 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" -#include "clang/Edit/EditedSource.h" #include "clang/Edit/Commit.h" +#include "clang/Edit/EditedSource.h" #include "clang/Edit/EditsReceiver.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/ErrorHandling.h" +#include "clang/Lex/Lexer.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> using namespace clang; @@ -47,6 +47,11 @@ static StringRef getImmediateMacroName(SourceLocation Loc, while (SM.isMacroArgExpansion(Loc)) Loc = SM.getImmediateExpansionRange(Loc).first; + // If the macro's spelling has no FileID, then it's actually a token paste + // or stringization (or similar) and not a macro at all. + if (!SM.getFileEntryForID(SM.getFileID(SM.getSpellingLoc(Loc)))) + return StringRef(); + // Find the spelling location of the start of the non-argument expansion // range. This is where the macro name was spelled in order to begin // expanding this macro. @@ -123,28 +128,18 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, const SourceManager *SM, DiagOrStoredDiag D) { assert(SM || Loc.isInvalid()); - + beginDiagnostic(D, Level); - - PresumedLoc PLoc; - if (Loc.isValid()) { - PLoc = SM->getPresumedLocForDisplay(Loc); - - // First, if this diagnostic is not in the main file, print out the - // "included from" lines. - emitIncludeStack(PLoc.getIncludeLoc(), Level, *SM); - } - - // Next, emit the actual diagnostic message. - emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D); - - // Only recurse if we have a valid location. - if (Loc.isValid()) { + + if (!Loc.isValid()) + // If we have no source location, just emit the diagnostic message. + emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D); + else { // Get the ranges into a local array we can hack on. SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), Ranges.end()); - - llvm::SmallVector<FixItHint, 8> MergedFixits; + + SmallVector<FixItHint, 8> MergedFixits; if (!FixItHints.empty()) { mergeFixits(FixItHints, *SM, LangOpts, MergedFixits); FixItHints = MergedFixits; @@ -155,15 +150,34 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, I != E; ++I) if (I->RemoveRange.isValid()) MutableRanges.push_back(I->RemoveRange); - - unsigned MacroDepth = 0; - emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints, *SM, - MacroDepth); + + SourceLocation UnexpandedLoc = Loc; + + // Find the ultimate expansion location for the diagnostic. + Loc = SM->getFileLoc(Loc); + + PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); + + // First, if this diagnostic is not in the main file, print out the + // "included from" lines. + emitIncludeStack(Loc, PLoc, Level, *SM); + + // Next, emit the actual diagnostic message and caret. + emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D); + emitCaret(Loc, Level, MutableRanges, FixItHints, *SM); + + // If this location is within a macro, walk from UnexpandedLoc up to Loc + // and produce a macro backtrace. + if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) { + unsigned MacroDepth = 0; + emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM, + MacroDepth); + } } - + LastLoc = Loc; LastLevel = Level; - + endDiagnostic(D, Level); } @@ -184,34 +198,55 @@ void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { /// repeated warnings occur within the same file. It also handles the logic /// of customizing the formatting and display of the include stack. /// +/// \param Loc The diagnostic location. +/// \param PLoc The presumed location of the diagnostic location. /// \param Level The diagnostic level of the message this stack pertains to. -/// \param Loc The include location of the current file (not the diagnostic -/// location). void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, + PresumedLoc PLoc, DiagnosticsEngine::Level Level, const SourceManager &SM) { + SourceLocation IncludeLoc = PLoc.getIncludeLoc(); + // Skip redundant include stacks altogether. - if (LastIncludeLoc == Loc) + if (LastIncludeLoc == IncludeLoc) return; - LastIncludeLoc = Loc; + + LastIncludeLoc = IncludeLoc; if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) return; - - emitIncludeStackRecursively(Loc, SM); + + if (IncludeLoc.isValid()) + emitIncludeStackRecursively(IncludeLoc, SM); + else { + emitModuleBuildStack(SM); + emitImportStack(Loc, SM); + } } /// \brief Helper to recursivly walk up the include stack and print each layer /// on the way back down. void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM) { - if (Loc.isInvalid()) + if (Loc.isInvalid()) { + emitModuleBuildStack(SM); return; + } - PresumedLoc PLoc = SM.getPresumedLoc(Loc); + PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); if (PLoc.isInvalid()) return; - + + // If this source location was imported from a module, print the module + // import stack rather than the + // FIXME: We want submodule granularity here. + std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc); + if (Imported.first.isValid()) { + // This location was imported by a module. Emit the module import stack. + emitImportStackRecursively(Imported.first, Imported.second, SM); + return; + } + // Emit the other include frames first. emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM); @@ -219,6 +254,56 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, emitIncludeLocation(Loc, PLoc, SM); } +/// \brief Emit the module import stack associated with the current location. +void DiagnosticRenderer::emitImportStack(SourceLocation Loc, + const SourceManager &SM) { + if (Loc.isInvalid()) { + emitModuleBuildStack(SM); + return; + } + + std::pair<SourceLocation, StringRef> NextImportLoc + = SM.getModuleImportLoc(Loc); + emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM); +} + +/// \brief Helper to recursivly walk up the import stack and print each layer +/// on the way back down. +void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc, + StringRef ModuleName, + const SourceManager &SM) { + if (Loc.isInvalid()) { + return; + } + + PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); + if (PLoc.isInvalid()) + return; + + // Emit the other import frames first. + std::pair<SourceLocation, StringRef> NextImportLoc + = SM.getModuleImportLoc(Loc); + emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM); + + // Emit the inclusion text/note. + emitImportLocation(Loc, PLoc, ModuleName, SM); +} + +/// \brief Emit the module build stack, for cases where a module is (re-)built +/// on demand. +void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) { + ModuleBuildStack Stack = SM.getModuleBuildStack(); + for (unsigned I = 0, N = Stack.size(); I != N; ++I) { + const SourceManager &CurSM = Stack[I].second.getManager(); + SourceLocation CurLoc = Stack[I].second; + emitBuildingModuleLocation(CurLoc, + CurSM.getPresumedLoc(CurLoc, + DiagOpts->ShowPresumedLoc), + Stack[I].first, + CurSM); + } +} + // 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. @@ -231,31 +316,58 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, // iff the FileID is the same. static void mapDiagnosticRanges( SourceLocation CaretLoc, - const SmallVectorImpl<CharSourceRange>& Ranges, - SmallVectorImpl<CharSourceRange>& SpellingRanges, + ArrayRef<CharSourceRange> Ranges, + SmallVectorImpl<CharSourceRange> &SpellingRanges, const SourceManager *SM) { FileID CaretLocFileID = SM->getFileID(CaretLoc); - for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(), + for (ArrayRef<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); + FileID BeginFileID = SM->getFileID(Begin); + FileID EndFileID = SM->getFileID(End); - // 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)) { + // Find the common parent for the beginning and end of the range. + + // First, crawl the expansion chain for the beginning of the range. + llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap; + while (Begin.isMacroID() && BeginFileID != EndFileID) { + BeginLocsMap[BeginFileID] = Begin; + Begin = SM->getImmediateExpansionRange(Begin).first; + BeginFileID = SM->getFileID(Begin); + } + + // Then, crawl the expansion chain for the end of the range. + if (BeginFileID != EndFileID) { + while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) { + End = SM->getImmediateExpansionRange(End).second; + EndFileID = SM->getFileID(End); + } + if (End.isMacroID()) { + Begin = BeginLocsMap[EndFileID]; + BeginFileID = EndFileID; + } + } + + while (Begin.isMacroID() && BeginFileID != CaretLocFileID) { + if (SM->isMacroArgExpansion(Begin)) { + Begin = SM->getImmediateSpellingLoc(Begin); End = SM->getImmediateSpellingLoc(End); } else { + Begin = SM->getImmediateExpansionRange(Begin).first; End = SM->getImmediateExpansionRange(End).second; } + BeginFileID = SM->getFileID(Begin); + if (BeginFileID != SM->getFileID(End)) { + // FIXME: Ugly hack to stop a crash; this code is making bad + // assumptions and it's too complicated for me to reason + // about. + Begin = End = SourceLocation(); + break; + } } // Return the spelling location of the beginning and end of the range. @@ -266,6 +378,16 @@ static void mapDiagnosticRanges( } } +void DiagnosticRenderer::emitCaret(SourceLocation Loc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM) { + SmallVector<CharSourceRange, 4> SpellingRanges; + mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); + emitCodeContext(Loc, Level, SpellingRanges, Hints, SM); +} + /// \brief Recursively emit notes for each macro expansion and caret /// diagnostics where appropriate. /// @@ -277,48 +399,24 @@ static void mapDiagnosticRanges( /// \param Level The diagnostic level currently being emitted. /// \param Ranges The underlined ranges for this code snippet. /// \param Hints The FixIt hints active for this diagnostic. -/// \param MacroSkipEnd The depth to stop skipping macro expansions. /// \param OnMacroInst The current depth of the macro expansion stack. -void DiagnosticRenderer::emitMacroExpansionsAndCarets( - SourceLocation Loc, - DiagnosticsEngine::Level Level, - SmallVectorImpl<CharSourceRange>& Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM, - unsigned &MacroDepth, - unsigned OnMacroInst) -{ +void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM, + unsigned &MacroDepth, + unsigned OnMacroInst) { assert(!Loc.isInvalid() && "must have a valid source location here"); - - // 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, SpellingRanges, Hints, SM); - return; - } - // Otherwise recurse through each macro expansion layer. - - // When processing macros, skip over the expansions leading up to - // a macro argument, and trace the argument's expansion stack instead. - Loc = SM.skipToMacroArgExpansion(Loc); - + + // Walk up to the caller of this macro, and produce a backtrace down to there. SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc); + if (OneLevelUp.isMacroID()) + emitMacroExpansions(OneLevelUp, Level, Ranges, Hints, SM, + MacroDepth, OnMacroInst + 1); + else + MacroDepth = OnMacroInst + 1; - emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, SM, MacroDepth, - OnMacroInst + 1); - - // Save the original location so we can find the spelling of the macro call. - SourceLocation MacroLoc = Loc; - - // Map the location. - Loc = SM.getImmediateMacroCalleeLoc(Loc); - unsigned MacroSkipStart = 0, MacroSkipEnd = 0; if (MacroDepth > DiagOpts->MacroBacktraceLimit && DiagOpts->MacroBacktraceLimit != 0) { @@ -326,11 +424,11 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( DiagOpts->MacroBacktraceLimit % 2; MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2; } - + // Whether to suppress printing this macro expansion. bool Suppressed = (OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd); - + if (Suppressed) { // Tell the user that we've skipped contexts. if (OnMacroInst == MacroSkipStart) { @@ -344,15 +442,27 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( return; } - // Map the ranges. + // Find the spelling location for the macro definition. We must use the + // spelling location here to avoid emitting a macro bactrace for the note. + SourceLocation SpellingLoc = Loc; + // If this is the expansion of a macro argument, point the caret at the + // use of the argument in the definition of the macro, not the expansion. + if (SM.isMacroArgExpansion(Loc)) + SpellingLoc = SM.getImmediateExpansionRange(Loc).first; + SpellingLoc = SM.getSpellingLoc(SpellingLoc); + + // Map the ranges into the FileID of the diagnostic location. SmallVector<CharSourceRange, 4> SpellingRanges; - mapDiagnosticRanges(MacroLoc, Ranges, SpellingRanges, &SM); + mapDiagnosticRanges(Loc, 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, + StringRef MacroName = getImmediateMacroName(Loc, SM, LangOpts); + if (MacroName.empty()) + Message << "expanded from here"; + else + Message << "expanded from macro '" << MacroName << "'"; + emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), SpellingRanges, ArrayRef<FixItHint>(), &SM); } @@ -370,6 +480,32 @@ void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc, emitNote(Loc, Message.str(), &SM); } +void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc, + PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) { + // Generate a note indicating the include location. + SmallString<200> MessageStorage; + llvm::raw_svector_ostream Message(MessageStorage); + Message << "in module '" << ModuleName << "' imported from " + << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; + emitNote(Loc, Message.str(), &SM); +} + +void +DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc, + PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) { + // Generate a note indicating the include location. + SmallString<200> MessageStorage; + llvm::raw_svector_ostream Message(MessageStorage); + Message << "while building module '" << ModuleName << "' imported from " + << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; + emitNote(Loc, Message.str(), &SM); +} + + void DiagnosticNoteRenderer::emitBasicNote(StringRef Message) { emitNote(SourceLocation(), Message, 0); } diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 2e9a791..6031ad2 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -11,8 +11,6 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclGroup.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/Preprocessor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/ChainedIncludesSource.h" #include "clang/Frontend/CompilerInstance.h" @@ -20,15 +18,18 @@ #include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/LayoutOverrideSource.h" #include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseAST.h" #include "clang/Serialization/ASTDeserializationListener.h" #include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/GlobalModuleIndex.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -#include "llvm/Support/Timer.h" using namespace clang; namespace { @@ -187,6 +188,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, setCurrentInput(Input, AST); + // Inform the diagnostic client we are processing a source file. + CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0); + HasBegunSourceFile = true; + // Set the shared objects, these are reset when we finish processing the // file, otherwise the CompilerInstance will happily destroy them. CI.setFileManager(&AST->getFileManager()); @@ -198,7 +203,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!BeginSourceFileAction(CI, InputFile)) goto failure; - /// Create the AST consumer. + // Create the AST consumer. CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile)); if (!CI.hasASTConsumer()) goto failure; @@ -246,16 +251,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, 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?"); + PPOpts.ImplicitPCHInclude = Dir->path(); + Found = true; break; } } @@ -279,8 +276,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!BeginSourceFileAction(CI, InputFile)) goto failure; - /// Create the AST context and consumer unless this is a preprocessor only - /// action. + // Create the AST context and consumer unless this is a preprocessor only + // action. if (!usesPreprocessorOnly()) { CI.createASTContext(); @@ -290,8 +287,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, goto failure; CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener()); - CI.getPreprocessor().setPPMutationListener( - Consumer->GetPPMutationListener()); if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) { // Convert headers to PCH and chain them. @@ -380,6 +375,15 @@ bool FrontendAction::Execute() { } else ExecuteAction(); + // If we are supposed to rebuild the global module index, do so now unless + // there were any module-build failures. + if (CI.shouldBuildGlobalModuleIndex() && CI.hasFileManager() && + CI.hasPreprocessor()) { + GlobalModuleIndex::writeIndex( + CI.getFileManager(), + CI.getPreprocessor().getHeaderSearchInfo().getModuleCachePath()); + } + return true; } diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 47063f7..5c7567f 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -9,16 +9,17 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/AST/ASTConsumer.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/Pragma.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Parse/Parser.h" #include "clang/Basic/FileManager.h" #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/Utils.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Pragma.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/Parser.h" +#include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/FileSystem.h" @@ -173,12 +174,12 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts, // Add includes for each of these headers. for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) { const FileEntry *Header = Module->Headers[I]; - Module->TopHeaders.insert(Header); + Module->addTopHeader(Header); addHeaderInclude(Header, Includes, LangOpts); } if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) { - Module->TopHeaders.insert(UmbrellaHeader); + Module->addTopHeader(UmbrellaHeader); if (Module->Parent) { // Include the umbrella header for submodules. addHeaderInclude(UmbrellaHeader, Includes, LangOpts); @@ -203,7 +204,7 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts, if (const FileEntry *Header = FileMgr.getFile(Dir->path())) { if (ModMap.isHeaderInUnavailableModule(Header)) continue; - Module->TopHeaders.insert(Header); + Module->addTopHeader(Header); } // Include this header umbrella header for submodules. @@ -273,19 +274,11 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module, HeaderContents); - 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(), - time(0)); - llvm::MemoryBuffer *HeaderContentsBuf - = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents); - CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf); - setCurrentInput(FrontendInputFile(InputName, getCurrentFileKind(), + llvm::MemoryBuffer *InputBuffer = + llvm::MemoryBuffer::getMemBufferCopy(HeaderContents, + Module::getModuleInputBufferName()); + // Ownership of InputBuffer will be transfered to the SourceManager. + setCurrentInput(FrontendInputFile(InputBuffer, getCurrentFileKind(), Module->IsSystem)); return true; } @@ -324,6 +317,130 @@ ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, return new ASTConsumer(); } +ASTConsumer *DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + return new ASTConsumer(); +} + +namespace { + /// \brief AST reader listener that dumps module information for a module + /// file. + class DumpModuleInfoListener : public ASTReaderListener { + llvm::raw_ostream &Out; + + public: + DumpModuleInfoListener(llvm::raw_ostream &Out) : Out(Out) { } + +#define DUMP_BOOLEAN(Value, Text) \ + Out.indent(4) << Text << ": " << (Value? "Yes" : "No") << "\n" + + virtual bool ReadFullVersionInformation(StringRef FullVersion) { + Out.indent(2) + << "Generated by " + << (FullVersion == getClangFullRepositoryVersion()? "this" + : "a different") + << " Clang: " << FullVersion << "\n"; + return ASTReaderListener::ReadFullVersionInformation(FullVersion); + } + + virtual bool ReadLanguageOptions(const LangOptions &LangOpts, + bool Complain) { + Out.indent(2) << "Language options:\n"; +#define LANGOPT(Name, Bits, Default, Description) \ + DUMP_BOOLEAN(LangOpts.Name, Description); +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + Out.indent(4) << Description << ": " \ + << static_cast<unsigned>(LangOpts.get##Name()) << "\n"; +#define VALUE_LANGOPT(Name, Bits, Default, Description) \ + Out.indent(4) << Description << ": " << LangOpts.Name << "\n"; +#define BENIGN_LANGOPT(Name, Bits, Default, Description) +#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#include "clang/Basic/LangOptions.def" + return false; + } + + virtual bool ReadTargetOptions(const TargetOptions &TargetOpts, + bool Complain) { + Out.indent(2) << "Target options:\n"; + Out.indent(4) << " Triple: " << TargetOpts.Triple << "\n"; + Out.indent(4) << " CPU: " << TargetOpts.CPU << "\n"; + Out.indent(4) << " ABI: " << TargetOpts.ABI << "\n"; + Out.indent(4) << " C++ ABI: " << TargetOpts.CXXABI << "\n"; + Out.indent(4) << " Linker version: " << TargetOpts.LinkerVersion << "\n"; + + if (!TargetOpts.FeaturesAsWritten.empty()) { + Out.indent(4) << "Target features:\n"; + for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); + I != N; ++I) { + Out.indent(6) << TargetOpts.FeaturesAsWritten[I] << "\n"; + } + } + + return false; + } + + virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, + bool Complain) { + Out.indent(2) << "Header search options:\n"; + Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n"; + DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes, + "Use builtin include directories [-nobuiltininc]"); + DUMP_BOOLEAN(HSOpts.UseStandardSystemIncludes, + "Use standard system include directories [-nostdinc]"); + DUMP_BOOLEAN(HSOpts.UseStandardCXXIncludes, + "Use standard C++ include directories [-nostdinc++]"); + DUMP_BOOLEAN(HSOpts.UseLibcxx, + "Use libc++ (rather than libstdc++) [-stdlib=]"); + return false; + } + + virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, + bool Complain, + std::string &SuggestedPredefines) { + Out.indent(2) << "Preprocessor options:\n"; + DUMP_BOOLEAN(PPOpts.UsePredefines, + "Uses compiler/target-specific predefines [-undef]"); + DUMP_BOOLEAN(PPOpts.DetailedRecord, + "Uses detailed preprocessing record (for indexing)"); + + if (!PPOpts.Macros.empty()) { + Out.indent(4) << "Predefined macros:\n"; + } + + for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator + I = PPOpts.Macros.begin(), IEnd = PPOpts.Macros.end(); + I != IEnd; ++I) { + Out.indent(6); + if (I->second) + Out << "-U"; + else + Out << "-D"; + Out << I->first << "\n"; + } + return false; + } +#undef DUMP_BOOLEAN + }; +} + +void DumpModuleInfoAction::ExecuteAction() { + // Set up the output file. + llvm::OwningPtr<llvm::raw_fd_ostream> OutFile; + StringRef OutputFileName = getCompilerInstance().getFrontendOpts().OutputFile; + if (!OutputFileName.empty() && OutputFileName != "-") { + std::string ErrorInfo; + OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str().c_str(), + ErrorInfo)); + } + llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs(); + + Out << "Information for module file '" << getCurrentFile() << "':\n"; + DumpModuleInfoListener Listener(Out); + ASTReader::readASTFileControlBlock(getCurrentFile(), + getCompilerInstance().getFileManager(), + Listener); +} + //===----------------------------------------------------------------------===// // Preprocessor Actions //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index ea4005f..f1823c6 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -13,7 +13,7 @@ using namespace clang; InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) { return llvm::StringSwitch<InputKind>(Extension) - .Case("ast", IK_AST) + .Cases("ast", "pcm", IK_AST) .Case("c", IK_C) .Cases("S", "s", IK_Asm) .Case("i", IK_PreprocessedC) diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 4fddd11..35eec56 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -14,19 +14,18 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" -#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Config/config.h" // C_INCLUDE_DIRS #include "clang/Lex/HeaderSearch.h" -#include "llvm/ADT/SmallString.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" - -#include "clang/Config/config.h" // C_INCLUDE_DIRS +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::frontend; @@ -44,19 +43,23 @@ class InitHeaderSearch { HeaderSearch &Headers; bool Verbose; std::string IncludeSysroot; - bool IsNotEmptyOrRoot; + bool HasSysroot; public: InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot) : Headers(HS), Verbose(verbose), IncludeSysroot(sysroot), - IsNotEmptyOrRoot(!(sysroot.empty() || sysroot == "/")) { + HasSysroot(!(sysroot.empty() || sysroot == "/")) { } - /// AddPath - Add the specified path to the specified group list. - void AddPath(const Twine &Path, IncludeDirGroup Group, - bool isCXXAware, bool isUserSupplied, - bool isFramework, bool IgnoreSysRoot = false); + /// AddPath - Add the specified path to the specified group list, prefixing + /// the sysroot if used. + void AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework); + + /// AddUnmappedPath - Add the specified path to the specified group list, + /// without performing any sysroot remapping. + void AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, + bool isFramework); /// AddSystemHeaderPrefix - Add the specified prefix to the system header /// prefix list. @@ -105,45 +108,52 @@ public: } // end anonymous namespace. -void InitHeaderSearch::AddPath(const Twine &Path, - IncludeDirGroup Group, bool isCXXAware, - bool isUserSupplied, bool isFramework, - bool IgnoreSysRoot) { - assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); - FileManager &FM = Headers.getFileMgr(); - - // Compute the actual path, taking into consideration -isysroot. - SmallString<256> MappedPathStorage; - StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); - - // Handle isysroot. - if ((Group == System || Group == CXXSystem) && !IgnoreSysRoot && +static bool CanPrefixSysroot(StringRef Path) { #if defined(_WIN32) - !MappedPathStr.empty() && - llvm::sys::path::is_separator(MappedPathStr[0]) && + return !Path.empty() && llvm::sys::path::is_separator(Path[0]); #else - llvm::sys::path::is_absolute(MappedPathStr) && + return llvm::sys::path::is_absolute(Path); #endif - IsNotEmptyOrRoot) { - MappedPathStorage.clear(); - MappedPathStr = - (IncludeSysroot + Path).toStringRef(MappedPathStorage); +} + +void InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, + bool isFramework) { + // Add the path with sysroot prepended, if desired and this is a system header + // group. + if (HasSysroot) { + SmallString<256> MappedPathStorage; + StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); + if (CanPrefixSysroot(MappedPathStr)) { + AddUnmappedPath(IncludeSysroot + Path, Group, isFramework); + return; + } } + AddUnmappedPath(Path, Group, isFramework); +} + +void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, + bool isFramework) { + assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); + + FileManager &FM = Headers.getFileMgr(); + SmallString<256> MappedPathStorage; + StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); + // Compute the DirectoryLookup type. SrcMgr::CharacteristicKind Type; - if (Group == Quoted || Group == Angled || Group == IndexHeaderMap) + if (Group == Quoted || Group == Angled || Group == IndexHeaderMap) { Type = SrcMgr::C_User; - else if (isCXXAware) - Type = SrcMgr::C_System; - else + } else if (Group == ExternCSystem) { Type = SrcMgr::C_ExternCSystem; - + } else { + Type = SrcMgr::C_System; + } // If the directory exists, add it. if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) { - IncludePath.push_back(std::make_pair(Group, DirectoryLookup(DE, Type, - isUserSupplied, isFramework))); + IncludePath.push_back( + std::make_pair(Group, DirectoryLookup(DE, Type, isFramework))); return; } @@ -153,8 +163,9 @@ void InitHeaderSearch::AddPath(const Twine &Path, if (const FileEntry *FE = FM.getFile(MappedPathStr)) { if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) { // It is a headermap, add it to the search path. - IncludePath.push_back(std::make_pair(Group, DirectoryLookup(HM, Type, - isUserSupplied, Group == IndexHeaderMap))); + IncludePath.push_back( + std::make_pair(Group, + DirectoryLookup(HM, Type, Group == IndexHeaderMap))); return; } } @@ -171,42 +182,42 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base, StringRef Dir64, const llvm::Triple &triple) { // Add the base dir - AddPath(Base, CXXSystem, true, false, false); + AddPath(Base, CXXSystem, false); // Add the multilib dirs llvm::Triple::ArchType arch = triple.getArch(); bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64; if (is64bit) - AddPath(Base + "/" + ArchDir + "/" + Dir64, CXXSystem, true, false, false); + AddPath(Base + "/" + ArchDir + "/" + Dir64, CXXSystem, false); else - AddPath(Base + "/" + ArchDir + "/" + Dir32, CXXSystem, true, false, false); + AddPath(Base + "/" + ArchDir + "/" + Dir32, CXXSystem, false); // Add the backward dir - AddPath(Base + "/backward", CXXSystem, true, false, false); + AddPath(Base + "/backward", CXXSystem, false); } void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base, StringRef Arch, StringRef Version) { AddPath(Base + "/" + Arch + "/" + Version + "/include/c++", - CXXSystem, true, false, false); + CXXSystem, false); AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch, - CXXSystem, true, false, false); + CXXSystem, false); AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward", - CXXSystem, true, false, false); + CXXSystem, false); } void InitHeaderSearch::AddMinGW64CXXPaths(StringRef Base, StringRef Version) { // Assumes Base is HeaderSearchOpts' ResourceDir AddPath(Base + "/../../../include/c++/" + Version, - CXXSystem, true, false, false); + CXXSystem, false); AddPath(Base + "/../../../include/c++/" + Version + "/x86_64-w64-mingw32", - CXXSystem, true, false, false); + CXXSystem, false); AddPath(Base + "/../../../include/c++/" + Version + "/i686-w64-mingw32", - CXXSystem, true, false, false); + CXXSystem, false); AddPath(Base + "/../../../include/c++/" + Version + "/backward", - CXXSystem, true, false, false); + CXXSystem, false); } void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, @@ -222,7 +233,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, break; default: // FIXME: temporary hack: hard-coded paths. - AddPath("/usr/local/include", System, true, false, false); + AddPath("/usr/local/include", System, false); break; } } @@ -234,7 +245,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, // supplied path. llvm::sys::Path P(HSOpts.ResourceDir); P.appendComponent("include"); - AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true); + AddUnmappedPath(P.str(), ExternCSystem, false); } // All remaining additions are for system include directories, early exit if @@ -250,7 +261,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, for (SmallVectorImpl<StringRef>::iterator i = dirs.begin(); i != dirs.end(); ++i) - AddPath(*i, System, false, false, false); + AddPath(*i, ExternCSystem, false); return; } @@ -260,68 +271,59 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, llvm_unreachable("Include management is handled in the driver."); case llvm::Triple::Haiku: - AddPath("/boot/common/include", System, true, false, false); - AddPath("/boot/develop/headers/os", System, true, false, false); - AddPath("/boot/develop/headers/os/app", System, true, false, false); - AddPath("/boot/develop/headers/os/arch", System, true, false, false); - AddPath("/boot/develop/headers/os/device", System, true, false, false); - AddPath("/boot/develop/headers/os/drivers", System, true, false, false); - AddPath("/boot/develop/headers/os/game", System, true, false, false); - AddPath("/boot/develop/headers/os/interface", System, true, false, false); - AddPath("/boot/develop/headers/os/kernel", System, true, false, false); - AddPath("/boot/develop/headers/os/locale", System, true, false, false); - AddPath("/boot/develop/headers/os/mail", System, true, false, false); - AddPath("/boot/develop/headers/os/media", System, true, false, false); - AddPath("/boot/develop/headers/os/midi", System, true, false, false); - AddPath("/boot/develop/headers/os/midi2", System, true, false, false); - AddPath("/boot/develop/headers/os/net", System, true, false, false); - AddPath("/boot/develop/headers/os/storage", System, true, false, false); - AddPath("/boot/develop/headers/os/support", System, true, false, false); - AddPath("/boot/develop/headers/os/translation", - System, true, false, false); - AddPath("/boot/develop/headers/os/add-ons/graphics", - System, true, false, false); - AddPath("/boot/develop/headers/os/add-ons/input_server", - System, true, false, false); - AddPath("/boot/develop/headers/os/add-ons/screen_saver", - System, true, false, false); - AddPath("/boot/develop/headers/os/add-ons/tracker", - System, true, false, false); - AddPath("/boot/develop/headers/os/be_apps/Deskbar", - System, true, false, false); - AddPath("/boot/develop/headers/os/be_apps/NetPositive", - System, true, false, false); - AddPath("/boot/develop/headers/os/be_apps/Tracker", - System, true, false, false); - AddPath("/boot/develop/headers/cpp", System, true, false, false); - AddPath("/boot/develop/headers/cpp/i586-pc-haiku", - System, true, false, false); - AddPath("/boot/develop/headers/3rdparty", System, true, false, false); - AddPath("/boot/develop/headers/bsd", System, true, false, false); - AddPath("/boot/develop/headers/glibc", System, true, false, false); - AddPath("/boot/develop/headers/posix", System, true, false, false); - AddPath("/boot/develop/headers", System, true, false, false); + AddPath("/boot/common/include", System, false); + AddPath("/boot/develop/headers/os", System, false); + AddPath("/boot/develop/headers/os/app", System, false); + AddPath("/boot/develop/headers/os/arch", System, false); + AddPath("/boot/develop/headers/os/device", System, false); + AddPath("/boot/develop/headers/os/drivers", System, false); + AddPath("/boot/develop/headers/os/game", System, false); + AddPath("/boot/develop/headers/os/interface", System, false); + AddPath("/boot/develop/headers/os/kernel", System, false); + AddPath("/boot/develop/headers/os/locale", System, false); + AddPath("/boot/develop/headers/os/mail", System, false); + AddPath("/boot/develop/headers/os/media", System, false); + AddPath("/boot/develop/headers/os/midi", System, false); + AddPath("/boot/develop/headers/os/midi2", System, false); + AddPath("/boot/develop/headers/os/net", System, false); + AddPath("/boot/develop/headers/os/storage", System, false); + AddPath("/boot/develop/headers/os/support", System, false); + AddPath("/boot/develop/headers/os/translation", System, false); + AddPath("/boot/develop/headers/os/add-ons/graphics", System, false); + AddPath("/boot/develop/headers/os/add-ons/input_server", System, false); + AddPath("/boot/develop/headers/os/add-ons/screen_saver", System, false); + AddPath("/boot/develop/headers/os/add-ons/tracker", System, false); + AddPath("/boot/develop/headers/os/be_apps/Deskbar", System, false); + AddPath("/boot/develop/headers/os/be_apps/NetPositive", System, false); + AddPath("/boot/develop/headers/os/be_apps/Tracker", System, false); + AddPath("/boot/develop/headers/cpp", System, false); + AddPath("/boot/develop/headers/cpp/i586-pc-haiku", System, false); + AddPath("/boot/develop/headers/3rdparty", System, false); + AddPath("/boot/develop/headers/bsd", System, false); + AddPath("/boot/develop/headers/glibc", System, false); + AddPath("/boot/develop/headers/posix", System, false); + AddPath("/boot/develop/headers", System, false); break; case llvm::Triple::RTEMS: break; case llvm::Triple::Cygwin: - AddPath("/usr/include/w32api", System, true, false, false); + AddPath("/usr/include/w32api", System, false); break; case llvm::Triple::MinGW32: { // mingw-w64 crt include paths llvm::sys::Path P(HSOpts.ResourceDir); P.appendComponent("../../../i686-w64-mingw32/include"); // <sysroot>/i686-w64-mingw32/include - AddPath(P.str(), System, true, false, false); + AddPath(P.str(), System, false); P = llvm::sys::Path(HSOpts.ResourceDir); P.appendComponent("../../../x86_64-w64-mingw32/include"); // <sysroot>/x86_64-w64-mingw32/include - AddPath(P.str(), System, true, false, false); + AddPath(P.str(), System, false); // mingw.org crt include paths P = llvm::sys::Path(HSOpts.ResourceDir); P.appendComponent("../../../include"); // <sysroot>/include - AddPath(P.str(), System, true, false, false); - AddPath("/mingw/include", System, true, false, false); + AddPath(P.str(), System, false); + AddPath("/mingw/include", System, false); #if defined(_WIN32) - AddPath("c:/mingw/include", System, true, false, false); + AddPath("c:/mingw/include", System, false); #endif } break; @@ -331,7 +333,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, } if ( os != llvm::Triple::RTEMS ) - AddPath("/usr/include", System, false, false, false); + AddPath("/usr/include", ExternCSystem, false); } void InitHeaderSearch:: @@ -408,7 +410,7 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp #endif break; case llvm::Triple::DragonFly: - AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false); + AddPath("/usr/include/c++/4.1", CXXSystem, false); break; case llvm::Triple::FreeBSD: // FreeBSD 8.0 @@ -474,16 +476,15 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, // Get foo/lib/c++/v1 P.appendComponent("c++"); P.appendComponent("v1"); - AddPath(P.str(), CXXSystem, true, false, false, true); + AddUnmappedPath(P.str(), CXXSystem, false); } } // On Solaris, include the support directory for things like xlocale and // fudged system headers. if (triple.getOS() == llvm::Triple::Solaris) - AddPath("/usr/include/c++/v1/support/solaris", CXXSystem, true, false, - false); + AddPath("/usr/include/c++/v1/support/solaris", CXXSystem, false); - AddPath("/usr/include/c++/v1", CXXSystem, true, false, false); + AddPath("/usr/include/c++/v1", CXXSystem, false); } else { AddDefaultCPlusPlusIncludePaths(triple, HSOpts); } @@ -494,8 +495,8 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, // Add the default framework include paths on Darwin. if (HSOpts.UseStandardSystemIncludes) { if (triple.isOSDarwin()) { - AddPath("/System/Library/Frameworks", System, true, false, true); - AddPath("/Library/Frameworks", System, true, false, true); + AddPath("/System/Library/Frameworks", System, true); + AddPath("/Library/Frameworks", System, true); } } } @@ -613,7 +614,7 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { for (path_iterator it = IncludePath.begin(), ie = IncludePath.end(); it != ie; ++it) { - if (it->first == System || + if (it->first == System || it->first == ExternCSystem || (!Lang.ObjC1 && !Lang.CPlusPlus && it->first == CSystem) || (/*FIXME !Lang.ObjC1 && */Lang.CPlusPlus && it->first == CXXSystem) || (Lang.ObjC1 && !Lang.CPlusPlus && it->first == ObjCSystem) || @@ -669,8 +670,11 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, // Add the user defined entries. for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) { const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i]; - Init.AddPath(E.Path, E.Group, !E.ImplicitExternC, E.IsUserSupplied, - E.IsFramework, E.IgnoreSysRoot); + if (E.IgnoreSysRoot) { + Init.AddUnmappedPath(E.Path, E.Group, E.IsFramework); + } else { + Init.AddPath(E.Path, E.Group, E.IsFramework); + } } Init.AddDefaultIncludePaths(Lang, Triple, HSOpts); diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 4bbd033..25cfac6 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -11,17 +11,17 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/Version.h" #include "clang/Frontend/Utils.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Version.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.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" @@ -307,7 +307,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, // C++11 [cpp.predefined]p1: // The name __cplusplus is defined to the value 201103L when compiling a // C++ translation unit. - if (LangOpts.CPlusPlus0x) + if (LangOpts.CPlusPlus11) Builder.defineMacro("__cplusplus", "201103L"); // C++03 [cpp.predefined]p1: // The name __cplusplus is defined to the value 199711L when compiling a @@ -377,7 +377,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (!LangOpts.GNUMode) Builder.defineMacro("__STRICT_ANSI__"); - if (LangOpts.CPlusPlus0x) + if (LangOpts.CPlusPlus11) Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__"); if (LangOpts.ObjC1) { @@ -490,6 +490,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder); DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder); DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder); + DefineTypeSize("__SIZE_MAX__", TI.getSizeType(), TI, Builder); DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder); DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder); @@ -507,6 +508,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, TI.getTypeWidth(TI.getWCharType()), TI, Builder); DefineTypeSizeof("__SIZEOF_WINT_T__", TI.getTypeWidth(TI.getWIntType()), TI, Builder); + if (TI.hasInt128Type()) + DefineTypeSizeof("__SIZEOF_INT128__", 128, TI, Builder); DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder); DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder); @@ -639,6 +642,16 @@ static void InitializePredefinedMacros(const TargetInfo &TI, "__attribute__((objc_ownership(none)))"); } + // OpenMP definition + if (LangOpts.OpenMP) { + // OpenMP 2.2: + // In implementations that support a preprocessor, the _OPENMP + // macro name is defined to have the decimal value yyyymm where + // yyyy and mm are the year and the month designations of the + // version of the OpenMP API that the implementation support. + Builder.defineMacro("_OPENMP", "201107"); + } + // Get other target #defines. TI.getTargetDefines(LangOpts, Builder); } @@ -772,15 +785,16 @@ void clang::InitializePreprocessor(Preprocessor &PP, AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i], PP.getFileManager()); + // Process -include-pch/-include-pth directives. + if (!InitOpts.ImplicitPCHInclude.empty()) + AddImplicitIncludePCH(Builder, PP, InitOpts.ImplicitPCHInclude); + if (!InitOpts.ImplicitPTHInclude.empty()) + AddImplicitIncludePTH(Builder, PP, InitOpts.ImplicitPTHInclude); + // Process -include directives. for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) { 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()); + AddImplicitInclude(Builder, Path, PP.getFileManager()); } // Exit the command line and go back to <built-in> (2 is LC_LEAVE). diff --git a/lib/Frontend/LayoutOverrideSource.cpp b/lib/Frontend/LayoutOverrideSource.cpp index e023250..924a640 100644 --- a/lib/Frontend/LayoutOverrideSource.cpp +++ b/lib/Frontend/LayoutOverrideSource.cpp @@ -8,8 +8,8 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/LayoutOverrideSource.h" #include "clang/AST/Decl.h" +#include "clang/Basic/CharInfo.h" #include "llvm/Support/raw_ostream.h" -#include <cctype> #include <fstream> #include <string> @@ -17,16 +17,17 @@ using namespace clang; /// \brief Parse a simple identifier. static std::string parseName(StringRef S) { - unsigned Offset = 0; - while (Offset < S.size() && - (isalpha(S[Offset]) || S[Offset] == '_' || - (Offset > 0 && isdigit(S[Offset])))) + if (S.empty() || !isIdentifierHead(S[0])) + return ""; + + unsigned Offset = 1; + while (Offset < S.size() && isIdentifierBody(S[Offset])) ++Offset; return S.substr(0, Offset).str(); } -LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) { +LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) { std::ifstream Input(Filename.str().c_str()); if (!Input.is_open()) return; @@ -128,10 +129,10 @@ LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) { continue; LineStr = LineStr.substr(Pos + strlen("FieldOffsets: [")); - while (!LineStr.empty() && isdigit(LineStr[0])) { + while (!LineStr.empty() && isDigit(LineStr[0])) { // Parse this offset. unsigned Idx = 1; - while (Idx < LineStr.size() && isdigit(LineStr[Idx])) + while (Idx < LineStr.size() && isDigit(LineStr[Idx])) ++Idx; unsigned long long Offset = 0; @@ -141,7 +142,7 @@ LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) { // Skip over this offset, the following comma, and any spaces. LineStr = LineStr.substr(Idx + 1); - while (!LineStr.empty() && isspace(LineStr[0])) + while (!LineStr.empty() && isWhitespace(LineStr[0])) LineStr = LineStr.substr(1); } } @@ -188,7 +189,7 @@ LayoutOverrideSource::layoutRecordType(const RecordDecl *Record, } void LayoutOverrideSource::dump() { - llvm::raw_ostream &OS = llvm::errs(); + raw_ostream &OS = llvm::errs(); for (llvm::StringMap<Layout>::iterator L = Layouts.begin(), LEnd = Layouts.end(); L != LEnd; ++L) { diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp index 3a04f18..0a22481 100644 --- a/lib/Frontend/LogDiagnosticPrinter.cpp +++ b/lib/Frontend/LogDiagnosticPrinter.cpp @@ -12,8 +12,8 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os, diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp index 992eeb0..ba83580 100644 --- a/lib/Frontend/MultiplexConsumer.cpp +++ b/lib/Frontend/MultiplexConsumer.cpp @@ -14,7 +14,6 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/MultiplexConsumer.h" - #include "clang/AST/ASTMutationListener.h" #include "clang/AST/DeclGroup.h" #include "clang/Serialization/ASTDeserializationListener.h" diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 30707dc..f70bd7c 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/Utils.h" +#include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/PreprocessorOutputOptions.h" @@ -21,12 +22,11 @@ #include "clang/Lex/Pragma.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/TokenConcatenation.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" -#include <cctype> +#include "llvm/Support/raw_ostream.h" #include <cstdio> using namespace clang; @@ -95,6 +95,7 @@ private: bool DisableLineMarkers; bool DumpDefines; bool UseLineDirective; + bool IsFirstFileEntered; public: PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream &os, bool lineMarkers, bool defines) @@ -107,6 +108,7 @@ public: EmittedDirectiveOnThisLine = false; FileType = SrcMgr::C_User; Initialized = false; + IsFirstFileEntered = false; // If we're in microsoft mode, use normal #line instead of line markers. UseLineDirective = PP.getLangOpts().MicrosoftExt; @@ -137,11 +139,15 @@ public: diag::Mapping Map, StringRef Str); bool HandleFirstTokOnLine(Token &Tok); + + /// Move to the line of the provided source location. This will + /// return true if the output stream required adjustment or if + /// the requested location is on the first line. bool MoveToLine(SourceLocation Loc) { PresumedLoc PLoc = SM.getPresumedLoc(Loc); if (PLoc.isInvalid()) return false; - return MoveToLine(PLoc.getLine()); + return MoveToLine(PLoc.getLine()) || (PLoc.getLine() == 1); } bool MoveToLine(unsigned LineNo); @@ -154,10 +160,10 @@ public: void HandleNewlinesInToken(const char *TokStr, unsigned Len); /// MacroDefined - This hook is called whenever a macro definition is seen. - void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI); + void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD); /// MacroUndefined - This hook is called whenever a macro #undef is seen. - void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI); + void MacroUndefined(const Token &MacroNameTok, const MacroDirective *MD); }; } // end anonymous namespace @@ -266,13 +272,25 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, Lexer::Stringify(CurFilename); FileType = NewFileType; - if (DisableLineMarkers) return; + if (DisableLineMarkers) { + startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false); + return; + } if (!Initialized) { WriteLineInfo(CurLine); Initialized = true; } + // Do not emit an enter marker for the main file (which we expect is the first + // entered file). This matches gcc, and improves compatibility with some tools + // which track the # line markers as a way to determine when the preprocessed + // output is in the context of the main file. + if (Reason == PPCallbacks::EnterFile && !IsFirstFileEntered) { + IsFirstFileEntered = true; + return; + } + switch (Reason) { case PPCallbacks::EnterFile: WriteLineInfo(CurLine, " 1", 2); @@ -299,7 +317,8 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) { /// MacroDefined - This hook is called whenever a macro definition is seen. void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, - const MacroInfo *MI) { + const MacroDirective *MD) { + const MacroInfo *MI = MD->getMacroInfo(); // Only print out macro definitions in -dD mode. if (!DumpDefines || // Ignore __FILE__ etc. @@ -311,7 +330,7 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, } void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok, - const MacroInfo *MI) { + const MacroDirective *MD) { // Only print out macro definitions in -dD mode. if (!DumpDefines) return; @@ -332,7 +351,7 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc, for (unsigned i = 0, e = Str.size(); i != e; ++i) { unsigned char Char = Str[i]; - if (isprint(Char) && Char != '\\' && Char != '"') + if (isPrintable(Char) && Char != '\\' && Char != '"') OS << (char)Char; else // Output anything hard as an octal escape. OS << '\\' @@ -357,7 +376,7 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, for (unsigned i = 0, e = Str.size(); i != e; ++i) { unsigned char Char = Str[i]; - if (isprint(Char) && Char != '\\' && Char != '"') + if (isPrintable(Char) && Char != '\\' && Char != '"') OS << (char)Char; else // Output anything hard as an octal escape. OS << '\\' @@ -496,6 +515,9 @@ struct UnknownPragmaHandler : public PragmaHandler { static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, PrintPPOutputPPCallbacks *Callbacks, raw_ostream &OS) { + bool DropComments = PP.getLangOpts().TraditionalCPP && + !PP.getCommentRetentionState(); + char Buffer[256]; Token PrevPrevTok, PrevTok; PrevPrevTok.startToken(); @@ -518,7 +540,13 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, OS << ' '; } - if (IdentifierInfo *II = Tok.getIdentifierInfo()) { + if (DropComments && Tok.is(tok::comment)) { + // Skip comments. Normally the preprocessor does not generate + // tok::comment nodes at all when not keeping comments, but under + // -traditional-cpp the lexer keeps /all/ whitespace, including comments. + SourceLocation StartLoc = Tok.getLocation(); + Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength())); + } else if (IdentifierInfo *II = Tok.getIdentifierInfo()) { OS << II->getName(); } else if (Tok.isLiteral() && !Tok.needsCleaning() && Tok.getLiteralData()) { @@ -530,7 +558,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, // Tokens that can contain embedded newlines need to adjust our current // line number. - if (Tok.getKind() == tok::comment) + if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown) Callbacks->HandleNewlinesInToken(TokPtr, Len); } else { std::string S = PP.getSpelling(Tok); @@ -538,7 +566,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, // Tokens that can contain embedded newlines need to adjust our current // line number. - if (Tok.getKind() == tok::comment) + if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown) Callbacks->HandleNewlinesInToken(&S[0], S.size()); } Callbacks->setEmittedTokensOnThisLine(); @@ -551,7 +579,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, } } -typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair; +typedef std::pair<const IdentifierInfo *, MacroInfo *> id_macro_pair; static int MacroIDCompare(const void* a, const void* b) { const id_macro_pair *LHS = static_cast<const id_macro_pair*>(a); const id_macro_pair *RHS = static_cast<const id_macro_pair*>(b); @@ -574,7 +602,7 @@ static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) { 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)); + MacrosByID.push_back(id_macro_pair(I->first, I->second->getMacroInfo())); } llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare); diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp index 5f8fc1e..4bb662b 100644 --- a/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -7,19 +7,19 @@ // //===----------------------------------------------------------------------===// -#include <vector> -#include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/DenseSet.h" +#include "clang/Frontend/SerializedDiagnosticPrinter.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" -#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" -#include "clang/Lex/Lexer.h" -#include "clang/Frontend/SerializedDiagnosticPrinter.h" #include "clang/Frontend/DiagnosticRenderer.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include <vector> using namespace clang; using namespace clang::serialized_diags; @@ -44,8 +44,8 @@ public: } }; -typedef llvm::SmallVector<uint64_t, 64> RecordData; -typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl; +typedef SmallVector<uint64_t, 64> RecordData; +typedef SmallVectorImpl<uint64_t> RecordDataImpl; class SDiagsWriter; @@ -89,10 +89,16 @@ protected: class SDiagsWriter : public DiagnosticConsumer { friend class SDiagsRenderer; -public: - explicit SDiagsWriter(llvm::raw_ostream *os, DiagnosticOptions *diags) - : LangOpts(0), DiagOpts(diags), Stream(Buffer), OS(os), - EmittedAnyDiagBlocks(false) { + + struct SharedState; + + explicit SDiagsWriter(IntrusiveRefCntPtr<SharedState> State) + : LangOpts(0), OriginalInstance(false), State(State) { } + +public: + SDiagsWriter(raw_ostream *os, DiagnosticOptions *diags) + : LangOpts(0), OriginalInstance(true), State(new SharedState(os, diags)) + { EmitPreamble(); } @@ -109,8 +115,7 @@ public: virtual void finish(); DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - // It makes no sense to clone this. - return 0; + return new SDiagsWriter(State); } private: @@ -175,50 +180,67 @@ private: /// \brief The version of the diagnostics file. enum { Version = 1 }; + /// \brief Language options, which can differ from one clone of this client + /// to another. const LangOptions *LangOpts; - llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; - - /// \brief The byte buffer for the serialized content. - SmallString<1024> Buffer; - /// \brief The BitStreamWriter for the serialized diagnostics. - llvm::BitstreamWriter Stream; + /// \brief Whether this is the original instance (rather than one of its + /// clones), responsible for writing the file at the end. + bool OriginalInstance; - /// \brief The name of the diagnostics file. - OwningPtr<llvm::raw_ostream> OS; - - /// \brief The set of constructed record abbreviations. - AbbreviationMap Abbrevs; + /// \brief State that is shared among the various clones of this diagnostic + /// consumer. + struct SharedState : RefCountedBase<SharedState> { + SharedState(raw_ostream *os, DiagnosticOptions *diags) + : DiagOpts(diags), Stream(Buffer), OS(os), EmittedAnyDiagBlocks(false) { } - /// \brief A utility buffer for constructing record content. - RecordData Record; + /// \brief Diagnostic options. + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; - /// \brief A text buffer for rendering diagnostic text. - SmallString<256> diagBuf; - - /// \brief The collection of diagnostic categories used. - llvm::DenseSet<unsigned> Categories; - - /// \brief The collection of files used. - llvm::DenseMap<const char *, unsigned> Files; + /// \brief The byte buffer for the serialized content. + SmallString<1024> Buffer; + + /// \brief The BitStreamWriter for the serialized diagnostics. + llvm::BitstreamWriter Stream; + + /// \brief The name of the diagnostics file. + OwningPtr<raw_ostream> OS; + + /// \brief The set of constructed record abbreviations. + AbbreviationMap Abbrevs; + + /// \brief A utility buffer for constructing record content. + RecordData Record; + + /// \brief A text buffer for rendering diagnostic text. + SmallString<256> diagBuf; + + /// \brief The collection of diagnostic categories used. + llvm::DenseSet<unsigned> Categories; + + /// \brief The collection of files used. + llvm::DenseMap<const char *, unsigned> Files; + + typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> > + DiagFlagsTy; - typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> > - DiagFlagsTy; + /// \brief Map for uniquing strings. + DiagFlagsTy DiagFlags; - /// \brief Map for uniquing strings. - DiagFlagsTy DiagFlags; + /// \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; + }; - /// \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; + /// \brief State shared among the various clones of this diagnostic consumer. + IntrusiveRefCntPtr<SharedState> State; }; } // end anonymous namespace namespace clang { namespace serialized_diags { -DiagnosticConsumer *create(llvm::raw_ostream *OS, - DiagnosticOptions *diags) { +DiagnosticConsumer *create(raw_ostream *OS, DiagnosticOptions *diags) { return new SDiagsWriter(OS, diags); } } // end namespace serialized_diags @@ -297,12 +319,12 @@ unsigned SDiagsWriter::getEmitFile(const char *FileName){ if (!FileName) return 0; - unsigned &entry = Files[FileName]; + unsigned &entry = State->Files[FileName]; if (entry) return entry; // Lazily generate the record for the file. - entry = Files.size(); + entry = State->Files.size(); RecordData Record; Record.push_back(RECORD_FILENAME); Record.push_back(entry); @@ -310,26 +332,28 @@ unsigned SDiagsWriter::getEmitFile(const char *FileName){ Record.push_back(0); // For legacy. StringRef Name(FileName); Record.push_back(Name.size()); - Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name); + State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME), Record, + Name); return entry; } void SDiagsWriter::EmitCharSourceRange(CharSourceRange R, const SourceManager &SM) { - Record.clear(); - Record.push_back(RECORD_SOURCE_RANGE); - AddCharSourceRangeToRecord(R, Record, SM); - Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record); + State->Record.clear(); + State->Record.push_back(RECORD_SOURCE_RANGE); + AddCharSourceRangeToRecord(R, State->Record, SM); + State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE), + State->Record); } /// \brief Emits the preamble of the diagnostics file. void SDiagsWriter::EmitPreamble() { // Emit the file header. - Stream.Emit((unsigned)'D', 8); - Stream.Emit((unsigned)'I', 8); - Stream.Emit((unsigned)'A', 8); - Stream.Emit((unsigned)'G', 8); + State->Stream.Emit((unsigned)'D', 8); + State->Stream.Emit((unsigned)'I', 8); + State->Stream.Emit((unsigned)'A', 8); + State->Stream.Emit((unsigned)'G', 8); EmitBlockInfoBlock(); EmitMetaBlock(); @@ -349,9 +373,12 @@ static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) { } void SDiagsWriter::EmitBlockInfoBlock() { - Stream.EnterBlockInfoBlock(3); + State->Stream.EnterBlockInfoBlock(3); using namespace llvm; + llvm::BitstreamWriter &Stream = State->Stream; + RecordData &Record = State->Record; + AbbreviationMap &Abbrevs = State->Abbrevs; // ==---------------------------------------------------------------------==// // The subsequent records and Abbrevs are for the "Meta" block. @@ -435,6 +462,10 @@ void SDiagsWriter::EmitBlockInfoBlock() { } void SDiagsWriter::EmitMetaBlock() { + llvm::BitstreamWriter &Stream = State->Stream; + RecordData &Record = State->Record; + AbbreviationMap &Abbrevs = State->Abbrevs; + Stream.EnterSubblock(BLOCK_META, 3); Record.clear(); Record.push_back(RECORD_VERSION); @@ -444,10 +475,10 @@ void SDiagsWriter::EmitMetaBlock() { } unsigned SDiagsWriter::getEmitCategory(unsigned int category) { - if (Categories.count(category)) + if (State->Categories.count(category)) return category; - Categories.insert(category); + State->Categories.insert(category); // We use a local version of 'Record' so that we can be generating // another record when we lazily generate one for the category entry. @@ -456,7 +487,8 @@ unsigned SDiagsWriter::getEmitCategory(unsigned int category) { Record.push_back(category); StringRef catName = DiagnosticIDs::getCategoryNameFromID(category); Record.push_back(catName.size()); - Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName); + State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record, + catName); return category; } @@ -473,9 +505,9 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, // Here we assume that FlagName points to static data whose pointer // value is fixed. This allows us to unique by diagnostic groups. const void *data = FlagName.data(); - std::pair<unsigned, StringRef> &entry = DiagFlags[data]; + std::pair<unsigned, StringRef> &entry = State->DiagFlags[data]; if (entry.first == 0) { - entry.first = DiagFlags.size(); + entry.first = State->DiagFlags.size(); entry.second = FlagName; // Lazily emit the string in a separate record. @@ -483,8 +515,8 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, Record.push_back(RECORD_DIAG_FLAG); Record.push_back(entry.first); Record.push_back(FlagName.size()); - Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG), - Record, FlagName); + State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG), + Record, FlagName); } return entry.first; @@ -496,31 +528,41 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, // for beginDiagnostic, in case associated notes are emitted before we get // there. if (DiagLevel != DiagnosticsEngine::Note) { - if (EmittedAnyDiagBlocks) + if (State->EmittedAnyDiagBlocks) ExitDiagBlock(); EnterDiagBlock(); - EmittedAnyDiagBlocks = true; + State->EmittedAnyDiagBlocks = true; } // Compute the diagnostic text. - diagBuf.clear(); - Info.FormatDiagnostic(diagBuf); + State->diagBuf.clear(); + Info.FormatDiagnostic(State->diagBuf); 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. + + // Make sure we bracket all notes as "sub-diagnostics". This matches + // the behavior in SDiagsRenderer::emitDiagnostic(). + if (DiagLevel == DiagnosticsEngine::Note) + EnterDiagBlock(); + EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel, - diagBuf, 0, &Info); + State->diagBuf, 0, &Info); + + if (DiagLevel == DiagnosticsEngine::Note) + ExitDiagBlock(); + return; } assert(Info.hasSourceManager() && LangOpts && "Unexpected diagnostic with valid location outside of a source file"); - SDiagsRenderer Renderer(*this, *LangOpts, &*DiagOpts); + SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts); Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, - diagBuf.str(), + State->diagBuf.str(), Info.getRanges(), llvm::makeArrayRef(Info.getFixItHints(), Info.getNumFixItHints()), @@ -534,6 +576,10 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, StringRef Message, const SourceManager *SM, DiagOrStoredDiag D) { + llvm::BitstreamWriter &Stream = State->Stream; + RecordData &Record = State->Record; + AbbreviationMap &Abbrevs = State->Abbrevs; + // Emit the RECORD_DIAG record. Record.clear(); Record.push_back(RECORD_DIAG); @@ -567,11 +613,11 @@ SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, } void SDiagsWriter::EnterDiagBlock() { - Stream.EnterSubblock(BLOCK_DIAG, 4); + State->Stream.EnterSubblock(BLOCK_DIAG, 4); } void SDiagsWriter::ExitDiagBlock() { - Stream.ExitBlock(); + State->Stream.ExitBlock(); } void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D, @@ -591,6 +637,10 @@ void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D, void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, ArrayRef<FixItHint> Hints, const SourceManager &SM) { + llvm::BitstreamWriter &Stream = State->Stream; + RecordData &Record = State->Record; + AbbreviationMap &Abbrevs = State->Abbrevs; + // Emit Source Ranges. for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) @@ -630,13 +680,17 @@ void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message, } void SDiagsWriter::finish() { + // The original instance is responsible for writing the file. + if (!OriginalInstance) + return; + // Finish off any diagnostic we were in the process of emitting. - if (EmittedAnyDiagBlocks) + if (State->EmittedAnyDiagBlocks) ExitDiagBlock(); // Write the generated bitstream to "Out". - OS->write((char *)&Buffer.front(), Buffer.size()); - OS->flush(); + State->OS->write((char *)&State->Buffer.front(), State->Buffer.size()); + State->OS->flush(); - OS.reset(0); + State->OS.reset(0); } diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index 35dabad..ca4ad60 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -8,19 +8,19 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/TextDiagnostic.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Basic/ConvertUTF.h" -#include "clang/Basic/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Locale.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Locale.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> -#include <cctype> using namespace clang; @@ -248,6 +248,7 @@ static void columnToByte(StringRef SourceLine, unsigned TabStop, out.back() = i; } +namespace { struct SourceColumnMap { SourceColumnMap(StringRef SourceLine, unsigned TabStop) : m_SourceLine(SourceLine) { @@ -313,14 +314,13 @@ private: }; // used in assert in selectInterestingSourceRegion() -namespace { struct char_out_of_range { const char lower,upper; char_out_of_range(char lower, char upper) : lower(lower), upper(upper) {} bool operator()(char c) { return c < lower || upper < c; } }; -} +} // end anonymous namespace /// \brief When the source code line we want to print is too long for /// the terminal, select the "interesting" region. @@ -348,11 +348,11 @@ static void selectInterestingSourceRegion(std::string &SourceLine, // correctly. unsigned CaretStart = 0, CaretEnd = CaretLine.size(); for (; CaretStart != CaretEnd; ++CaretStart) - if (!isspace(static_cast<unsigned char>(CaretLine[CaretStart]))) + if (!isWhitespace(CaretLine[CaretStart])) break; for (; CaretEnd != CaretStart; --CaretEnd) - if (!isspace(static_cast<unsigned char>(CaretLine[CaretEnd - 1]))) + if (!isWhitespace(CaretLine[CaretEnd - 1])) break; // caret has already been inserted into CaretLine so the above whitespace @@ -363,11 +363,11 @@ static void selectInterestingSourceRegion(std::string &SourceLine, if (!FixItInsertionLine.empty()) { unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size(); for (; FixItStart != FixItEnd; ++FixItStart) - if (!isspace(static_cast<unsigned char>(FixItInsertionLine[FixItStart]))) + if (!isWhitespace(FixItInsertionLine[FixItStart])) break; for (; FixItEnd != FixItStart; --FixItEnd) - if (!isspace(static_cast<unsigned char>(FixItInsertionLine[FixItEnd - 1]))) + if (!isWhitespace(FixItInsertionLine[FixItEnd - 1])) break; CaretStart = std::min(FixItStart, CaretStart); @@ -423,14 +423,13 @@ static void selectInterestingSourceRegion(std::string &SourceLine, // 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 && - isspace(static_cast<unsigned char>(SourceLine[NewStart]))) + while (NewStart && isWhitespace(SourceLine[NewStart])) NewStart = map.startOfPreviousColumn(NewStart); // Skip over this bit of "interesting" text. while (NewStart) { unsigned Prev = map.startOfPreviousColumn(NewStart); - if (isspace(static_cast<unsigned char>(SourceLine[Prev]))) + if (isWhitespace(SourceLine[Prev])) break; NewStart = Prev; } @@ -450,13 +449,11 @@ static void selectInterestingSourceRegion(std::string &SourceLine, // Skip over any whitespace we see here; we're looking for // another bit of interesting text. // FIXME: Detect non-ASCII whitespace characters too. - while (NewEnd < SourceLine.size() && - isspace(static_cast<unsigned char>(SourceLine[NewEnd]))) + while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd])) NewEnd = map.startOfNextColumn(NewEnd); // Skip over this bit of "interesting" text. - while (NewEnd < SourceLine.size() && - !isspace(static_cast<unsigned char>(SourceLine[NewEnd]))) + while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd])) NewEnd = map.startOfNextColumn(NewEnd); assert(map.byteToColumn(NewEnd) != -1); @@ -517,7 +514,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine, /// greater than or equal to Idx or, if no such character exists, /// returns the end of the string. static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) { - while (Idx < Length && isspace(Str[Idx])) + while (Idx < Length && isWhitespace(Str[Idx])) ++Idx; return Idx; } @@ -562,7 +559,7 @@ static unsigned findEndOfWord(unsigned Start, StringRef Str, char EndPunct = findMatchingPunctuation(Str[Start]); if (!EndPunct) { // This is a normal word. Just find the first space character. - while (End < Length && !isspace(Str[End])) + while (End < Length && !isWhitespace(Str[End])) ++End; return End; } @@ -581,7 +578,7 @@ static unsigned findEndOfWord(unsigned Start, StringRef Str, } // Find the first space character after the punctuation ended. - while (End < Length && !isspace(Str[End])) + while (End < Length && !isWhitespace(Str[End])) ++End; unsigned PunctWordLength = End - Start; @@ -884,6 +881,178 @@ void TextDiagnostic::emitIncludeLocation(SourceLocation Loc, OS << "In included file:\n"; } +void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) { + if (DiagOpts->ShowLocation) + OS << "In module '" << ModuleName << "' imported from " + << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; + else + OS << "In module " << ModuleName << "':\n"; +} + +void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc, + PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) { + if (DiagOpts->ShowLocation && PLoc.getFilename()) + OS << "While building module '" << ModuleName << "' imported from " + << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; + else + OS << "While building module '" << ModuleName << "':\n"; +} + +/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. +static void highlightRange(const CharSourceRange &R, + unsigned LineNo, FileID FID, + const SourceColumnMap &map, + std::string &CaretLine, + const SourceManager &SM, + const LangOptions &LangOpts) { + if (!R.isValid()) return; + + SourceLocation Begin = R.getBegin(); + SourceLocation End = R.getEnd(); + + unsigned StartLineNo = SM.getExpansionLineNumber(Begin); + if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) + return; // No intersection. + + unsigned EndLineNo = SM.getExpansionLineNumber(End); + if (EndLineNo < LineNo || SM.getFileID(End) != FID) + return; // No intersection. + + // Compute the column number of the start. + unsigned StartColNo = 0; + if (StartLineNo == LineNo) { + StartColNo = SM.getExpansionColumnNumber(Begin); + if (StartColNo) --StartColNo; // Zero base the col #. + } + + // Compute the column number of the end. + unsigned EndColNo = map.getSourceLine().size(); + if (EndLineNo == LineNo) { + EndColNo = SM.getExpansionColumnNumber(End); + if (EndColNo) { + --EndColNo; // Zero base the col #. + + // Add in the length of the token, so that we cover multi-char tokens if + // this is a token range. + if (R.isTokenRange()) + EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts); + } else { + EndColNo = CaretLine.size(); + } + } + + assert(StartColNo <= EndColNo && "Invalid range!"); + + // Check that a token range does not highlight only whitespace. + if (R.isTokenRange()) { + // Pick the first non-whitespace column. + while (StartColNo < map.getSourceLine().size() && + (map.getSourceLine()[StartColNo] == ' ' || + map.getSourceLine()[StartColNo] == '\t')) + StartColNo = map.startOfNextColumn(StartColNo); + + // Pick the last non-whitespace column. + if (EndColNo > map.getSourceLine().size()) + EndColNo = map.getSourceLine().size(); + while (EndColNo && + (map.getSourceLine()[EndColNo-1] == ' ' || + map.getSourceLine()[EndColNo-1] == '\t')) + EndColNo = map.startOfPreviousColumn(EndColNo); + + // If the start/end passed each other, then we are trying to highlight a + // range that just exists in whitespace, which must be some sort of other + // bug. + assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); + } + + assert(StartColNo <= map.getSourceLine().size() && "Invalid range!"); + assert(EndColNo <= map.getSourceLine().size() && "Invalid range!"); + + // Fill the range with ~'s. + StartColNo = map.byteToContainingColumn(StartColNo); + EndColNo = map.byteToContainingColumn(EndColNo); + + assert(StartColNo <= EndColNo && "Invalid range!"); + if (CaretLine.size() < EndColNo) + CaretLine.resize(EndColNo,' '); + std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~'); +} + +static std::string buildFixItInsertionLine(unsigned LineNo, + const SourceColumnMap &map, + ArrayRef<FixItHint> Hints, + const SourceManager &SM, + const DiagnosticOptions *DiagOpts) { + std::string FixItInsertionLine; + if (Hints.empty() || !DiagOpts->ShowFixits) + return FixItInsertionLine; + unsigned PrevHintEndCol = 0; + + for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); + I != E; ++I) { + if (!I->CodeToInsert.empty()) { + // We have an insertion hint. Determine whether the inserted + // code contains no newlines and is on the same line as the caret. + std::pair<FileID, unsigned> HintLocInfo + = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); + if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && + StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) { + // Insert the new code into the line just below the code + // that the user wrote. + // Note: When modifying this function, be very careful about what is a + // "column" (printed width, platform-dependent) and what is a + // "byte offset" (SourceManager "column"). + unsigned HintByteOffset + = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1; + + // The hint must start inside the source or right at the end + assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1); + 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 + // completion. This is sort of the best we can do when two hints appear + // to overlap. + // + // Note that if this hint is located immediately after the previous + // hint, no space will be added, since the location is more important. + if (HintCol < PrevHintEndCol) + HintCol = PrevHintEndCol + 1; + + // FIXME: This function handles multibyte characters in the source, but + // not in the fixits. This assertion is intended to catch unintended + // use of multibyte characters in fixits. If we decide to do this, we'll + // have to track separate byte widths for the source and fixit lines. + assert((size_t)llvm::sys::locale::columnWidth(I->CodeToInsert) == + I->CodeToInsert.size()); + + // This relies on one byte per column in our fixit hints. + // This should NOT use HintByteOffset, because the source might have + // Unicode characters in earlier columns. + unsigned LastColumnModified = HintCol + I->CodeToInsert.size(); + if (LastColumnModified > FixItInsertionLine.size()) + FixItInsertionLine.resize(LastColumnModified, ' '); + + std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(), + FixItInsertionLine.begin() + HintCol); + + PrevHintEndCol = LastColumnModified; + } else { + FixItInsertionLine.clear(); + break; + } + } + } + + expandTabs(FixItInsertionLine, DiagOpts->TabStop); + + return FixItInsertionLine; +} + /// \brief Emit a code snippet and caret line. /// /// This routine emits a single line's code snippet and caret line.. @@ -924,18 +1093,26 @@ void TextDiagnostic::emitSnippetAndCaret( unsigned LineNo = SM.getLineNumber(FID, FileOffset); unsigned ColNo = SM.getColumnNumber(FID, FileOffset); + + // Arbitrarily stop showing snippets when the line is too long. + static const ptrdiff_t MaxLineLengthToPrint = 4096; + if (ColNo > MaxLineLengthToPrint) + return; // Rewind from the current position to the start of the line. const char *TokPtr = BufStart+FileOffset; const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. - // Compute the line end. Scan forward from the error position to the end of // the line. const char *LineEnd = TokPtr; while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') ++LineEnd; + // Arbitrarily stop showing snippets when the line is too long. + if (LineEnd - LineStart > MaxLineLengthToPrint) + return; + // Copy the line of code into an std::string for ease of manipulation. std::string SourceLine(LineStart, LineEnd); @@ -949,7 +1126,7 @@ void TextDiagnostic::emitSnippetAndCaret( for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) - highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM); + highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts); // Next, insert the caret itself. ColNo = sourceColMap.byteToContainingColumn(ColNo-1); @@ -959,7 +1136,8 @@ void TextDiagnostic::emitSnippetAndCaret( std::string FixItInsertionLine = buildFixItInsertionLine(LineNo, sourceColMap, - Hints, SM); + Hints, SM, + DiagOpts.getPtr()); // If the source line is too long for our terminal, select only the // "interesting" source region within that line. @@ -1041,157 +1219,6 @@ void TextDiagnostic::emitSnippet(StringRef line) { OS << '\n'; } -/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. -void TextDiagnostic::highlightRange(const CharSourceRange &R, - unsigned LineNo, FileID FID, - const SourceColumnMap &map, - std::string &CaretLine, - const SourceManager &SM) { - if (!R.isValid()) return; - - SourceLocation Begin = R.getBegin(); - SourceLocation End = R.getEnd(); - - unsigned StartLineNo = SM.getExpansionLineNumber(Begin); - if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) - return; // No intersection. - - unsigned EndLineNo = SM.getExpansionLineNumber(End); - if (EndLineNo < LineNo || SM.getFileID(End) != FID) - return; // No intersection. - - // Compute the column number of the start. - unsigned StartColNo = 0; - if (StartLineNo == LineNo) { - StartColNo = SM.getExpansionColumnNumber(Begin); - if (StartColNo) --StartColNo; // Zero base the col #. - } - - // Compute the column number of the end. - unsigned EndColNo = map.getSourceLine().size(); - if (EndLineNo == LineNo) { - EndColNo = SM.getExpansionColumnNumber(End); - if (EndColNo) { - --EndColNo; // Zero base the col #. - - // Add in the length of the token, so that we cover multi-char tokens if - // this is a token range. - if (R.isTokenRange()) - EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts); - } else { - EndColNo = CaretLine.size(); - } - } - - assert(StartColNo <= EndColNo && "Invalid range!"); - - // Check that a token range does not highlight only whitespace. - if (R.isTokenRange()) { - // Pick the first non-whitespace column. - while (StartColNo < map.getSourceLine().size() && - (map.getSourceLine()[StartColNo] == ' ' || - map.getSourceLine()[StartColNo] == '\t')) - StartColNo = map.startOfNextColumn(StartColNo); - - // Pick the last non-whitespace column. - if (EndColNo > map.getSourceLine().size()) - EndColNo = map.getSourceLine().size(); - while (EndColNo-1 && - (map.getSourceLine()[EndColNo-1] == ' ' || - map.getSourceLine()[EndColNo-1] == '\t')) - EndColNo = map.startOfPreviousColumn(EndColNo); - - // If the start/end passed each other, then we are trying to highlight a - // range that just exists in whitespace, which must be some sort of other - // bug. - assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); - } - - assert(StartColNo <= map.getSourceLine().size() && "Invalid range!"); - assert(EndColNo <= map.getSourceLine().size() && "Invalid range!"); - - // Fill the range with ~'s. - StartColNo = map.byteToContainingColumn(StartColNo); - EndColNo = map.byteToContainingColumn(EndColNo); - - assert(StartColNo <= EndColNo && "Invalid range!"); - if (CaretLine.size() < EndColNo) - CaretLine.resize(EndColNo,' '); - std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~'); -} - -std::string TextDiagnostic::buildFixItInsertionLine( - unsigned LineNo, - const SourceColumnMap &map, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { - - std::string FixItInsertionLine; - if (Hints.empty() || !DiagOpts->ShowFixits) - return FixItInsertionLine; - unsigned PrevHintEndCol = 0; - - for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); - I != E; ++I) { - if (!I->CodeToInsert.empty()) { - // We have an insertion hint. Determine whether the inserted - // code contains no newlines and is on the same line as the caret. - std::pair<FileID, unsigned> HintLocInfo - = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); - if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && - StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) { - // Insert the new code into the line just below the code - // that the user wrote. - // Note: When modifying this function, be very careful about what is a - // "column" (printed width, platform-dependent) and what is a - // "byte offset" (SourceManager "column"). - unsigned HintByteOffset - = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1; - - // The hint must start inside the source or right at the end - assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1); - 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 - // completion. This is sort of the best we can do when two hints appear - // to overlap. - // - // Note that if this hint is located immediately after the previous - // hint, no space will be added, since the location is more important. - if (HintCol < PrevHintEndCol) - HintCol = PrevHintEndCol + 1; - - // FIXME: This function handles multibyte characters in the source, but - // not in the fixits. This assertion is intended to catch unintended - // use of multibyte characters in fixits. If we decide to do this, we'll - // have to track separate byte widths for the source and fixit lines. - assert((size_t)llvm::sys::locale::columnWidth(I->CodeToInsert) == - I->CodeToInsert.size()); - - // This relies on one byte per column in our fixit hints. - // This should NOT use HintByteOffset, because the source might have - // Unicode characters in earlier columns. - unsigned LastColumnModified = HintCol + I->CodeToInsert.size(); - if (LastColumnModified > FixItInsertionLine.size()) - FixItInsertionLine.resize(LastColumnModified, ' '); - - std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(), - FixItInsertionLine.begin() + HintCol); - - PrevHintEndCol = LastColumnModified; - } else { - FixItInsertionLine.clear(); - break; - } - } - } - - expandTabs(FixItInsertionLine, DiagOpts->TabStop); - - return FixItInsertionLine; -} - void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints, const SourceManager &SM) { if (!DiagOpts->ShowParseableFixits) diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp index 57105f1..039475a 100644 --- a/lib/Frontend/TextDiagnosticBuffer.cpp +++ b/lib/Frontend/TextDiagnosticBuffer.cpp @@ -42,17 +42,37 @@ void TextDiagnosticBuffer::HandleDiagnostic(DiagnosticsEngine::Level Level, } } +/// \brief Escape diagnostic texts to avoid problems when they are fed into the +/// diagnostic formatter a second time. +static StringRef escapeDiag(StringRef Str, SmallVectorImpl<char> &Buf) { + size_t Pos = Str.find('%'); + if (Pos == StringRef::npos) + return Str; + + // We found a '%'. Replace this and all following '%' with '%%'. + Buf.clear(); + Buf.append(Str.data(), Str.data() + Pos); + for (size_t I = Pos, E = Str.size(); I != E; ++I) { + if (Str[I] == '%') + Buf.push_back('%'); + Buf.push_back(Str[I]); + } + + return StringRef(Buf.data(), Buf.size()); +} + void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const { + SmallVector<char, 64> Buf; // FIXME: Flush the diagnostics in order. for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it) Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, - it->second.c_str())); + escapeDiag(it->second, Buf))); for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it) Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Warning, - it->second.c_str())); + escapeDiag(it->second, Buf))); for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it) Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note, - it->second.c_str())); + escapeDiag(it->second, Buf))); } DiagnosticConsumer *TextDiagnosticBuffer::clone(DiagnosticsEngine &) const { diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index aa7a61a..010f649 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -17,10 +17,10 @@ #include "clang/Basic/SourceManager.h" #include "clang/Frontend/TextDiagnostic.h" #include "clang/Lex/Lexer.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/ADT/SmallString.h" #include <algorithm> using namespace clang; diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index 1750946..82f6e91 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -11,8 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/FileManager.h" #include "clang/Frontend/VerifyDiagnosticConsumer.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/FileManager.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Lex/HeaderSearch.h" @@ -20,7 +21,6 @@ #include "llvm/ADT/SmallString.h" #include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" -#include <cctype> using namespace clang; typedef VerifyDiagnosticConsumer::Directive Directive; @@ -234,7 +234,7 @@ public: break; if (!EnsureStartOfWord // Check if string literal starts a new word. - || P == Begin || isspace(P[-1]) + || P == Begin || isWhitespace(P[-1]) // Or it could be preceeded by the start of a comment. || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*') && P[-2] == '/')) @@ -253,7 +253,7 @@ public: // Skip zero or more whitespace. void SkipWhitespace() { - for (; C < End && isspace(*C); ++C) + for (; C < End && isWhitespace(*C); ++C) ; } diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index f789b7f..b7547b9 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -22,13 +22,13 @@ // #include "clang/Frontend/Utils.h" #include "clang/Basic/Diagnostic.h" -#include "clang/Sema/SemaDiagnostic.h" -#include "clang/Lex/LexDiagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/LexDiagnostic.h" +#include "clang/Sema/SemaDiagnostic.h" +#include <algorithm> #include <cstring> #include <utility> -#include <algorithm> using namespace clang; // EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning @@ -48,13 +48,15 @@ static void EmitUnknownDiagWarning(DiagnosticsEngine &Diags, } void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, - const DiagnosticOptions &Opts) { + const DiagnosticOptions &Opts, + bool ReportDiags) { Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); Diags.setShowOverloads(Opts.getShowOverloads()); Diags.setElideType(Opts.ElideType); Diags.setPrintTemplateTree(Opts.ShowTemplateTree); + Diags.setWarnOnSpellCheck(Opts.WarnOnSpellCheck); Diags.setShowColors(Opts.ShowColors); // Handle -ferror-limit @@ -75,7 +77,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, else Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Ignore); - llvm::SmallVector<diag::kind, 10> _Diags; + SmallVector<diag::kind, 10> _Diags; const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs = Diags.getDiagnosticIDs(); // We parse the warning options twice. The first pass sets diagnostic state, @@ -84,6 +86,12 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, // conflicting options. for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) { bool SetDiagnostic = (Report == 0); + + // If we've set the diagnostic state and are not reporting diagnostics then + // we're done. + if (!SetDiagnostic && !ReportDiags) + break; + for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { StringRef Opt = Opts.Warnings[i]; StringRef OrigOpt = Opts.Warnings[i]; |