diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend')
22 files changed, 2535 insertions, 1548 deletions
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp index 28d312a..54bb282 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp @@ -31,22 +31,23 @@ using namespace clang; namespace { class ASTPrinter : public ASTConsumer { - llvm::raw_ostream &Out; + raw_ostream &Out; bool Dump; public: - ASTPrinter(llvm::raw_ostream* o = NULL, bool Dump = false) + ASTPrinter(raw_ostream* o = NULL, bool Dump = false) : Out(o? *o : llvm::outs()), Dump(Dump) { } virtual void HandleTranslationUnit(ASTContext &Context) { - PrintingPolicy Policy = Context.PrintingPolicy; + PrintingPolicy Policy = Context.getPrintingPolicy(); Policy.Dump = Dump; - Context.getTranslationUnitDecl()->print(Out, Policy); + Context.getTranslationUnitDecl()->print(Out, Policy, /*Indentation=*/0, + /*PrintInstantiation=*/true); } }; } // end anonymous namespace -ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) { +ASTConsumer *clang::CreateASTPrinter(raw_ostream* out) { return new ASTPrinter(out); } @@ -95,7 +96,7 @@ ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); } namespace { class DeclContextPrinter : public ASTConsumer { - llvm::raw_ostream& Out; + raw_ostream& Out; public: DeclContextPrinter() : Out(llvm::errs()) {} @@ -117,34 +118,34 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, case Decl::Namespace: { Out << "[namespace] "; const NamespaceDecl* ND = cast<NamespaceDecl>(DC); - Out << ND; + Out << *ND; break; } case Decl::Enum: { const EnumDecl* ED = cast<EnumDecl>(DC); - if (ED->isDefinition()) + if (ED->isCompleteDefinition()) Out << "[enum] "; else Out << "<enum> "; - Out << ED; + Out << *ED; break; } case Decl::Record: { const RecordDecl* RD = cast<RecordDecl>(DC); - if (RD->isDefinition()) + if (RD->isCompleteDefinition()) Out << "[struct] "; else Out << "<struct> "; - Out << RD; + Out << *RD; break; } case Decl::CXXRecord: { const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC); - if (RD->isDefinition()) + if (RD->isCompleteDefinition()) Out << "[class] "; else Out << "<class> "; - Out << RD << ' ' << DC; + Out << *RD << ' ' << DC; break; } case Decl::ObjCMethod: @@ -177,7 +178,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "[function] "; else Out << "<function> "; - Out << FD; + Out << *FD; // Print the parameters. Out << "("; bool PrintComma = false; @@ -187,7 +188,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << ", "; else PrintComma = true; - Out << *I; + Out << **I; } Out << ")"; break; @@ -200,7 +201,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ method) "; else Out << "<c++ method> "; - Out << D; + Out << *D; // Print the parameters. Out << "("; bool PrintComma = false; @@ -210,7 +211,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << ", "; else PrintComma = true; - Out << *I; + Out << **I; } Out << ")"; @@ -230,7 +231,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ ctor) "; else Out << "<c++ ctor> "; - Out << D; + Out << *D; // Print the parameters. Out << "("; bool PrintComma = false; @@ -240,7 +241,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << ", "; else PrintComma = true; - Out << *I; + Out << **I; } Out << ")"; @@ -259,7 +260,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ dtor) "; else Out << "<c++ dtor> "; - Out << D; + Out << *D; // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); @@ -275,7 +276,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ conversion) "; else Out << "<c++ conversion> "; - Out << D; + Out << *D; // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); @@ -285,7 +286,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } default: - assert(0 && "a decl that inherits DeclContext isn't handled"); + llvm_unreachable("a decl that inherits DeclContext isn't handled"); } Out << "\n"; @@ -322,53 +323,53 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } case Decl::IndirectField: { IndirectFieldDecl* IFD = cast<IndirectFieldDecl>(*I); - Out << "<IndirectField> " << IFD << '\n'; + Out << "<IndirectField> " << *IFD << '\n'; break; } case Decl::Label: { LabelDecl *LD = cast<LabelDecl>(*I); - Out << "<Label> " << LD << '\n'; + Out << "<Label> " << *LD << '\n'; break; } case Decl::Field: { FieldDecl *FD = cast<FieldDecl>(*I); - Out << "<field> " << FD << '\n'; + Out << "<field> " << *FD << '\n'; break; } case Decl::Typedef: case Decl::TypeAlias: { TypedefNameDecl* TD = cast<TypedefNameDecl>(*I); - Out << "<typedef> " << TD << '\n'; + Out << "<typedef> " << *TD << '\n'; break; } case Decl::EnumConstant: { EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I); - Out << "<enum constant> " << ECD << '\n'; + Out << "<enum constant> " << *ECD << '\n'; break; } case Decl::Var: { VarDecl* VD = cast<VarDecl>(*I); - Out << "<var> " << VD << '\n'; + Out << "<var> " << *VD << '\n'; break; } case Decl::ImplicitParam: { ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I); - Out << "<implicit parameter> " << IPD << '\n'; + Out << "<implicit parameter> " << *IPD << '\n'; break; } case Decl::ParmVar: { ParmVarDecl* PVD = cast<ParmVarDecl>(*I); - Out << "<parameter> " << PVD << '\n'; + Out << "<parameter> " << *PVD << '\n'; break; } case Decl::ObjCProperty: { ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I); - Out << "<objc property> " << OPD << '\n'; + Out << "<objc property> " << *OPD << '\n'; break; } case Decl::FunctionTemplate: { FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I); - Out << "<function template> " << FTD << '\n'; + Out << "<function template> " << *FTD << '\n'; break; } case Decl::FileScopeAsm: { @@ -381,17 +382,17 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } case Decl::NamespaceAlias: { NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I); - Out << "<namespace alias> " << NAD << '\n'; + Out << "<namespace alias> " << *NAD << '\n'; break; } case Decl::ClassTemplate: { ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I); - Out << "<class template> " << CTD << '\n'; + Out << "<class template> " << *CTD << '\n'; break; } default: Out << "DeclKind: " << DK << '"' << *I << "\"\n"; - assert(0 && "decl unhandled"); + llvm_unreachable("decl unhandled"); } } } @@ -404,10 +405,10 @@ ASTConsumer *clang::CreateDeclContextPrinter() { namespace { class ASTDumpXML : public ASTConsumer { - llvm::raw_ostream &OS; + raw_ostream &OS; public: - ASTDumpXML(llvm::raw_ostream &OS) : OS(OS) {} + ASTDumpXML(raw_ostream &OS) : OS(OS) {} void HandleTranslationUnit(ASTContext &C) { C.getTranslationUnitDecl()->dumpXML(OS); @@ -415,6 +416,6 @@ public: }; } -ASTConsumer *clang::CreateASTDumperXML(llvm::raw_ostream &OS) { +ASTConsumer *clang::CreateASTDumperXML(raw_ostream &OS) { return new ASTDumpXML(OS); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp index 3905b99..cb195d1 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp @@ -17,12 +17,12 @@ using namespace clang; ASTConsumer *ASTMergeAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return AdaptedAction->CreateASTConsumer(CI, InFile); } bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI, - llvm::StringRef Filename) { + StringRef Filename) { // FIXME: This is a hack. We need a better way to communicate the // AST file, compiler instance, and file name than member variables // of FrontendAction. @@ -41,8 +41,8 @@ void ASTMergeAction::ExecuteAction() { llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(CI.getDiagnostics().getDiagnosticIDs()); for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { - llvm::IntrusiveRefCntPtr<Diagnostic> - Diags(new Diagnostic(DiagIDs, CI.getDiagnostics().getClient(), + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> + Diags(new DiagnosticsEngine(DiagIDs, CI.getDiagnostics().getClient(), /*ShouldOwnClient=*/false)); ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, CI.getFileSystemOpts(), false); @@ -93,8 +93,8 @@ bool ASTMergeAction::usesPreprocessorOnly() const { return AdaptedAction->usesPreprocessorOnly(); } -bool ASTMergeAction::usesCompleteTranslationUnit() { - return AdaptedAction->usesCompleteTranslationUnit(); +TranslationUnitKind ASTMergeAction::getTranslationUnitKind() { + return AdaptedAction->getTranslationUnitKind(); } bool ASTMergeAction::hasPCHSupport() const { diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp index 5b0a52c..032adf3 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp @@ -29,7 +29,6 @@ #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/Utils.h" #include "clang/Serialization/ASTReader.h" -#include "clang/Serialization/ASTSerializationListener.h" #include "clang/Serialization/ASTWriter.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" @@ -45,6 +44,8 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Timer.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Mutex.h" #include "llvm/Support/CrashRecoveryContext.h" #include <cstdlib> #include <cstdio> @@ -65,7 +66,7 @@ namespace { Start = TimeRecord::getCurrentTime(); } - void setOutput(const llvm::Twine &Output) { + void setOutput(const Twine &Output) { if (WantTiming) this->Output = Output.str(); } @@ -96,10 +97,9 @@ static llvm::sys::cas_flag ActiveASTUnitObjects; ASTUnit::ASTUnit(bool _MainFileIsAST) : OnlyLocalDecls(false), CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), - CompleteTranslationUnit(true), WantTiming(getenv("LIBCLANG_TIMING")), + TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")), OwnsRemappedFileBuffers(true), NumStoredDiagnosticsFromDriver(0), - ConcurrencyCheckValue(CheckUnlocked), PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0), ShouldCacheCodeCompletionResults(false), NestedMacroExpansions(true), @@ -114,7 +114,6 @@ ASTUnit::ASTUnit(bool _MainFileIsAST) } ASTUnit::~ASTUnit() { - ConcurrencyCheckValue = CheckLocked; CleanTemporaryFiles(); if (!PreambleFile.empty()) llvm::sys::Path(PreambleFile).eraseFromDisk(); @@ -185,7 +184,7 @@ static unsigned getDeclShowContexts(NamedDecl *ND, // In Objective-C, you can only be a subclass of another Objective-C class if (isa<ObjCInterfaceDecl>(ND)) - Contexts |= (1 << (CodeCompletionContext::CCC_ObjCSuperclass - 1)); + Contexts |= (1 << (CodeCompletionContext::CCC_ObjCInterfaceName - 1)); // Deal with tag names. if (isa<EnumDecl>(ND)) { @@ -236,7 +235,7 @@ void ASTUnit::CacheCodeCompletionResults() { // Gather the set of global code completions. typedef CodeCompletionResult Result; - llvm::SmallVector<Result, 8> Results; + SmallVector<Result, 8> Results; CachedCompletionAllocator = new GlobalCodeCompletionAllocator; TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator, Results); @@ -375,33 +374,61 @@ namespace { /// \brief Gathers information from ASTReader that will be used to initialize /// a Preprocessor. class ASTInfoCollector : public ASTReaderListener { + Preprocessor &PP; + ASTContext &Context; LangOptions &LangOpt; HeaderSearch &HSI; - std::string &TargetTriple; + llvm::IntrusiveRefCntPtr<TargetInfo> &Target; std::string &Predefines; unsigned &Counter; unsigned NumHeaderInfos; + bool InitializedLanguage; public: - ASTInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI, - std::string &TargetTriple, std::string &Predefines, + ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt, + HeaderSearch &HSI, + llvm::IntrusiveRefCntPtr<TargetInfo> &Target, + std::string &Predefines, unsigned &Counter) - : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple), - Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {} + : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), Target(Target), + Predefines(Predefines), Counter(Counter), NumHeaderInfos(0), + InitializedLanguage(false) {} virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { + if (InitializedLanguage) + return false; + LangOpt = LangOpts; + + // Initialize the preprocessor. + PP.Initialize(*Target); + + // Initialize the ASTContext + Context.InitBuiltinTypes(*Target); + + InitializedLanguage = true; return false; } - virtual bool ReadTargetTriple(llvm::StringRef Triple) { - TargetTriple = Triple; + virtual bool ReadTargetTriple(StringRef Triple) { + // If we've already initialized the target, don't do it again. + if (Target) + return false; + + // FIXME: This is broken, we should store the TargetOptions in the AST file. + TargetOptions TargetOpts; + TargetOpts.ABI = ""; + TargetOpts.CXXABI = ""; + TargetOpts.CPU = ""; + TargetOpts.Features.clear(); + TargetOpts.Triple = Triple; + Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), TargetOpts); return false; } virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, - llvm::StringRef OriginalFileName, + StringRef OriginalFileName, std::string &SuggestedPredefines, FileManager &FileMgr) { Predefines = Buffers[0].Data; @@ -420,28 +447,34 @@ public: } }; -class StoredDiagnosticClient : public DiagnosticClient { - llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags; +class StoredDiagnosticConsumer : public DiagnosticConsumer { + SmallVectorImpl<StoredDiagnostic> &StoredDiags; public: - explicit StoredDiagnosticClient( - llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) + explicit StoredDiagnosticConsumer( + SmallVectorImpl<StoredDiagnostic> &StoredDiags) : StoredDiags(StoredDiags) { } - virtual void HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info); + virtual void HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info); + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + // Just drop any diagnostics that come from cloned consumers; they'll + // have different source managers anyway. + return new IgnoringDiagConsumer(); + } }; /// \brief RAII object that optionally captures diagnostics, if /// there is no diagnostic client to capture them already. class CaptureDroppedDiagnostics { - Diagnostic &Diags; - StoredDiagnosticClient Client; - DiagnosticClient *PreviousClient; + DiagnosticsEngine &Diags; + StoredDiagnosticConsumer Client; + DiagnosticConsumer *PreviousClient; public: - CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags, - llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) + CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags, + SmallVectorImpl<StoredDiagnostic> &StoredDiags) : Diags(Diags), Client(StoredDiags), PreviousClient(0) { if (RequestCapture || Diags.getClient() == 0) { @@ -460,10 +493,10 @@ public: } // anonymous namespace -void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) { +void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) { // Default implementation (Warnings/errors count). - DiagnosticClient::HandleDiagnostic(Level, Info); + DiagnosticConsumer::HandleDiagnostic(Level, Info); StoredDiags.push_back(StoredDiagnostic(Level, Info)); } @@ -472,37 +505,32 @@ const std::string &ASTUnit::getOriginalSourceFileName() { return OriginalSourceFile; } -const std::string &ASTUnit::getASTFileName() { - assert(isMainFileAST() && "Not an ASTUnit from an AST file!"); - return static_cast<ASTReader *>(Ctx->getExternalSource())->getFileName(); -} - -llvm::MemoryBuffer *ASTUnit::getBufferForFile(llvm::StringRef Filename, +llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename, std::string *ErrorStr) { assert(FileMgr); return FileMgr->getBufferForFile(Filename, ErrorStr); } /// \brief Configure the diagnostics object for use with ASTUnit. -void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<Diagnostic> &Diags, +void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<DiagnosticsEngine> &Diags, const char **ArgBegin, const char **ArgEnd, ASTUnit &AST, bool CaptureDiagnostics) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. DiagnosticOptions DiagOpts; - DiagnosticClient *Client = 0; + DiagnosticConsumer *Client = 0; if (CaptureDiagnostics) - Client = new StoredDiagnosticClient(AST.StoredDiagnostics); + Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics); Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd- ArgBegin, ArgBegin, Client); } else if (CaptureDiagnostics) { - Diags->setClient(new StoredDiagnosticClient(AST.StoredDiagnostics)); + Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics)); } } ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags, + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags, const FileSystemOptions &FileSystemOpts, bool OnlyLocalDecls, RemappedFile *RemappedFiles, @@ -513,8 +541,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> ASTUnitCleanup(AST.get()); - llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, - llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.getPtr()); ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics); @@ -576,25 +604,41 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, // Gather Info for preprocessor construction later on. - LangOptions LangInfo; HeaderSearch &HeaderInfo = *AST->HeaderInfo.get(); - std::string TargetTriple; std::string Predefines; unsigned Counter; llvm::OwningPtr<ASTReader> Reader; - Reader.reset(new ASTReader(AST->getSourceManager(), AST->getFileManager(), - AST->getDiagnostics())); + AST->PP = new Preprocessor(AST->getDiagnostics(), AST->ASTFileLangOpts, + /*Target=*/0, AST->getSourceManager(), HeaderInfo, + *AST, + /*IILookup=*/0, + /*OwnsHeaderSearch=*/false, + /*DelayInitialization=*/true); + Preprocessor &PP = *AST->PP; + + AST->Ctx = new ASTContext(AST->ASTFileLangOpts, + AST->getSourceManager(), + /*Target=*/0, + PP.getIdentifierTable(), + PP.getSelectorTable(), + PP.getBuiltinInfo(), + /* size_reserve = */0, + /*DelayInitialization=*/true); + ASTContext &Context = *AST->Ctx; + + Reader.reset(new ASTReader(PP, Context)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTReader> ReaderCleanup(Reader.get()); - Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple, - Predefines, Counter)); + Reader->setListener(new ASTInfoCollector(*AST->PP, Context, + AST->ASTFileLangOpts, HeaderInfo, + AST->Target, Predefines, Counter)); - switch (Reader->ReadAST(Filename, ASTReader::MainFile)) { + switch (Reader->ReadAST(Filename, serialization::MK_MainFile)) { case ASTReader::Success: break; @@ -606,39 +650,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, AST->OriginalSourceFile = Reader->getOriginalSourceFile(); - // AST file loaded successfully. Now create the preprocessor. - - // Get information about the target being compiled for. - // - // FIXME: This is broken, we should store the TargetOptions in the AST file. - TargetOptions TargetOpts; - TargetOpts.ABI = ""; - TargetOpts.CXXABI = ""; - TargetOpts.CPU = ""; - TargetOpts.Features.clear(); - TargetOpts.Triple = TargetTriple; - AST->Target = TargetInfo::CreateTargetInfo(AST->getDiagnostics(), - TargetOpts); - AST->PP = new Preprocessor(AST->getDiagnostics(), LangInfo, *AST->Target, - AST->getSourceManager(), HeaderInfo); - Preprocessor &PP = *AST->PP; - PP.setPredefines(Reader->getSuggestedPredefines()); PP.setCounterValue(Counter); - Reader->setPreprocessor(PP); - - // Create and initialize the ASTContext. - - AST->Ctx = new ASTContext(LangInfo, - AST->getSourceManager(), - *AST->Target, - PP.getIdentifierTable(), - PP.getSelectorTable(), - PP.getBuiltinInfo(), - /* size_reserve = */0); - ASTContext &Context = *AST->Ctx; - - Reader->InitializeContext(Context); // Attach the AST reader to the AST context as an external AST // source, so that declarations will be deserialized from the @@ -710,10 +723,8 @@ void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) { return; } - if (ObjCClassDecl *Class = llvm::dyn_cast<ObjCClassDecl>(D)) { - for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end(); - I != IEnd; ++I) - AddTopLevelDeclarationToHash(I->getInterface(), Hash); + if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(D)) { + AddTopLevelDeclarationToHash(Class->getForwardInterfaceDecl(), Hash); return; } } @@ -752,7 +763,7 @@ public: ASTUnit &Unit; virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { CI.getPreprocessor().addPPCallbacks( new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue())); return new TopLevelDeclTrackerConsumer(Unit, @@ -763,22 +774,20 @@ public: TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {} virtual bool hasCodeCompletionSupport() const { return false; } - virtual bool usesCompleteTranslationUnit() { - return Unit.isCompleteTranslationUnit(); + virtual TranslationUnitKind getTranslationUnitKind() { + return Unit.getTranslationUnitKind(); } }; -class PrecompilePreambleConsumer : public PCHGenerator, - public ASTSerializationListener { +class PrecompilePreambleConsumer : public PCHGenerator { ASTUnit &Unit; unsigned &Hash; std::vector<Decl *> TopLevelDecls; public: - PrecompilePreambleConsumer(ASTUnit &Unit, - const Preprocessor &PP, bool Chaining, - const char *isysroot, llvm::raw_ostream *Out) - : PCHGenerator(PP, "", Chaining, isysroot, Out), Unit(Unit), + PrecompilePreambleConsumer(ASTUnit &Unit, const Preprocessor &PP, + StringRef isysroot, raw_ostream *Out) + : PCHGenerator(PP, "", /*IsModule=*/false, isysroot, Out), Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()) { Hash = 0; } @@ -809,15 +818,6 @@ public: getWriter().getDeclID(TopLevelDecls[I])); } } - - virtual void SerializedPreprocessedEntity(PreprocessedEntity *Entity, - uint64_t Offset) { - Unit.addPreprocessedEntityFromPreamble(Offset); - } - - virtual ASTSerializationListener *GetASTSerializationListener() { - return this; - } }; class PrecompilePreambleAction : public ASTFrontendAction { @@ -827,27 +827,27 @@ public: explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit) {} virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { std::string Sysroot; std::string OutputFile; - llvm::raw_ostream *OS = 0; - bool Chaining; + raw_ostream *OS = 0; if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, - OS, Chaining)) + OS)) return 0; - const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? - Sysroot.c_str() : 0; + if (!CI.getFrontendOpts().RelocatablePCH) + Sysroot.clear(); + CI.getPreprocessor().addPPCallbacks( new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue())); - return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Chaining, - isysroot, OS); + return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Sysroot, + OS); } virtual bool hasCodeCompletionSupport() const { return false; } virtual bool hasASTFileSupport() const { return false; } - virtual bool usesCompleteTranslationUnit() { return false; } + virtual TranslationUnitKind getTranslationUnitKind() { return TU_Prefix; } }; } @@ -873,7 +873,10 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(Clang.get()); - Clang->setInvocation(&*Invocation); + llvm::IntrusiveRefCntPtr<CompilerInvocation> + CCInvocation(new CompilerInvocation(*Invocation)); + + Clang->setInvocation(CCInvocation.getPtr()); OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second; // Set up diagnostics, capturing any diagnostics that would @@ -913,16 +916,13 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // Clear out old caches and data. TopLevelDecls.clear(); - PreprocessedEntities.clear(); CleanTemporaryFiles(); - PreprocessedEntitiesByFile.clear(); if (!OverrideMainBuffer) { StoredDiagnostics.erase( StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver, StoredDiagnostics.end()); TopLevelDeclsInPreamble.clear(); - PreprocessedEntitiesInPreamble.clear(); } // Create a file manager object to provide access to and cache the filesystem. @@ -936,13 +936,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts(); PreprocessorOpts.DetailedRecordIncludesNestedMacroExpansions = NestedMacroExpansions; - std::string PriorImplicitPCHInclude; if (OverrideMainBuffer) { PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine; - PriorImplicitPCHInclude = PreprocessorOpts.ImplicitPCHInclude; PreprocessorOpts.ImplicitPCHInclude = PreambleFile; PreprocessorOpts.DisablePCHValidation = true; @@ -961,9 +959,6 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // Keep track of the override buffer; SavedMainFileBuffer = OverrideMainBuffer; - } else { - PreprocessorOpts.PrecompiledPreambleBytes.first = 0; - PreprocessorOpts.PrecompiledPreambleBytes.second = false; } llvm::OwningPtr<TopLevelDeclTrackerAction> Act( @@ -976,7 +971,14 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second, Clang->getFrontendOpts().Inputs[0].first)) goto error; - + + if (OverrideMainBuffer) { + std::string ModName = PreambleFile; + TranslateStoredDiagnostics(Clang->getModuleManager(), ModName, + getSourceManager(), PreambleDiagnostics, + StoredDiagnostics); + } + Act->Execute(); // Steal the created target, context, and preprocessor. @@ -990,21 +992,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { Act->EndSourceFile(); - // Remove the overridden buffer we used for the preamble. - if (OverrideMainBuffer) { - PreprocessorOpts.eraseRemappedFile( - PreprocessorOpts.remapped_file_buffer_end() - 1); - PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude; - } - return false; error: // Remove the overridden buffer we used for the preamble. if (OverrideMainBuffer) { - PreprocessorOpts.eraseRemappedFile( - PreprocessorOpts.remapped_file_buffer_end() - 1); - PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude; delete OverrideMainBuffer; SavedMainFileBuffer = 0; } @@ -1041,7 +1033,7 @@ static std::string GetPreamblePCHPath() { P.createDirectoryOnDisk(true); P.appendComponent("preamble"); P.appendSuffix("pch"); - if (P.createTemporaryFileOnDisk()) + if (P.makeUnique(/*reuse_current=*/false, /*ErrMsg*/0)) return std::string(); return P.str(); @@ -1118,12 +1110,14 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, CreatedBuffer = true; } - return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer, MaxLines)); + return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer, + Invocation.getLangOpts(), + MaxLines)); } static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old, unsigned NewSize, - llvm::StringRef NewName) { + StringRef NewName) { llvm::MemoryBuffer *Result = llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName); memcpy(const_cast<char*>(Result->getBufferStart()), @@ -1170,7 +1164,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble = ComputePreamble(*PreambleInvocation, MaxLines, CreatedPreambleBuffer); - // If ComputePreamble() Take ownership of the + // If ComputePreamble() Take ownership of the preamble buffer. llvm::OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer; if (CreatedPreambleBuffer) OwnedPreambleBuffer.reset(NewPreamble.first); @@ -1197,7 +1191,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( if (Preamble.size() == NewPreamble.second.first && PreambleEndsAtStartOfLine == NewPreamble.second.second && NewPreamble.first->getBufferSize() < PreambleReservedSize-2 && - memcmp(&Preamble[0], NewPreamble.first->getBufferStart(), + memcmp(Preamble.getBufferStart(), NewPreamble.first->getBufferStart(), NewPreamble.second.first) == 0) { // The preamble has not changed. We may be able to re-use the precompiled // preamble. @@ -1271,10 +1265,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( ProcessWarningOptions(getDiagnostics(), PreambleInvocation->getDiagnosticOpts()); getDiagnostics().setNumWarnings(NumWarningsInPreamble); - if (StoredDiagnostics.size() > NumStoredDiagnosticsInPreamble) - StoredDiagnostics.erase( - StoredDiagnostics.begin() + NumStoredDiagnosticsInPreamble, - StoredDiagnostics.end()); // Create a version of the main file buffer that is padded to // buffer size we reserved when creating the preamble. @@ -1291,6 +1281,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // We can't reuse the previously-computed preamble. Build a new one. Preamble.clear(); + PreambleDiagnostics.clear(); llvm::sys::Path(PreambleFile).eraseFromDisk(); PreambleRebuildCounter = 1; } else if (!AllowRebuild) { @@ -1332,7 +1323,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Save the preamble text for later; we'll need to compare against it for // subsequent reparses. - Preamble.assign(NewPreamble.first->getBufferStart(), + StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].second; + Preamble.assign(FileMgr->getFile(MainFilename), + NewPreamble.first->getBufferStart(), NewPreamble.first->getBufferStart() + NewPreamble.second.first); PreambleEndsAtStartOfLine = NewPreamble.second.second; @@ -1353,7 +1346,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Tell the compiler invocation to generate a temporary precompiled header. FrontendOpts.ProgramAction = frontend::GeneratePCH; - FrontendOpts.ChainedPCH = true; // FIXME: Generate the precompiled header into memory? FrontendOpts.OutputFile = PreamblePCHPath; PreprocessorOpts.PrecompiledPreambleBytes.first = 0; @@ -1406,8 +1398,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( StoredDiagnostics.end()); TopLevelDecls.clear(); TopLevelDeclsInPreamble.clear(); - PreprocessedEntities.clear(); - PreprocessedEntitiesInPreamble.clear(); // Create a file manager object to provide access to and cache the filesystem. Clang->setFileManager(new FileManager(Clang->getFileSystemOpts())); @@ -1438,17 +1428,24 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); TopLevelDeclsInPreamble.clear(); - PreprocessedEntities.clear(); - PreprocessedEntitiesInPreamble.clear(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); return 0; } + // Transfer any diagnostics generated when parsing the preamble into the set + // of preamble diagnostics. + PreambleDiagnostics.clear(); + PreambleDiagnostics.insert(PreambleDiagnostics.end(), + StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver, + StoredDiagnostics.end()); + StoredDiagnostics.erase( + StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver, + StoredDiagnostics.end()); + // Keep track of the preamble we precompiled. PreambleFile = FrontendOpts.OutputFile; - NumStoredDiagnosticsInPreamble = StoredDiagnostics.size(); NumWarningsInPreamble = getDiagnostics().getNumWarnings(); // Keep track of all of the files that the source manager knows about, @@ -1501,69 +1498,12 @@ void ASTUnit::RealizeTopLevelDeclsFromPreamble() { TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end()); } -void ASTUnit::RealizePreprocessedEntitiesFromPreamble() { - if (!PP) - return; - - PreprocessingRecord *PPRec = PP->getPreprocessingRecord(); - if (!PPRec) - return; - - ExternalPreprocessingRecordSource *External = PPRec->getExternalSource(); - if (!External) - return; - - for (unsigned I = 0, N = PreprocessedEntitiesInPreamble.size(); I != N; ++I) { - if (PreprocessedEntity *PE - = External->ReadPreprocessedEntityAtOffset( - PreprocessedEntitiesInPreamble[I])) - PreprocessedEntities.push_back(PE); - } - - if (PreprocessedEntities.empty()) - return; - - PreprocessedEntities.insert(PreprocessedEntities.end(), - PPRec->begin(true), PPRec->end(true)); -} - -ASTUnit::pp_entity_iterator ASTUnit::pp_entity_begin() { - if (!PreprocessedEntitiesInPreamble.empty() && - PreprocessedEntities.empty()) - RealizePreprocessedEntitiesFromPreamble(); - - if (PreprocessedEntities.empty()) - if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord()) - return PPRec->begin(true); - - return PreprocessedEntities.begin(); -} - -ASTUnit::pp_entity_iterator ASTUnit::pp_entity_end() { - if (!PreprocessedEntitiesInPreamble.empty() && - PreprocessedEntities.empty()) - RealizePreprocessedEntitiesFromPreamble(); - - if (PreprocessedEntities.empty()) - if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord()) - return PPRec->end(true); - - return PreprocessedEntities.end(); -} - -unsigned ASTUnit::getMaxPCHLevel() const { - if (!getOnlyLocalDecls()) - return Decl::MaxPCHLevel; - - return 0; -} - -llvm::StringRef ASTUnit::getMainFileName() const { +StringRef ASTUnit::getMainFileName() const { return Invocation->getFrontendOpts().Inputs[0].second; } ASTUnit *ASTUnit::create(CompilerInvocation *CI, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags) { + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags) { llvm::OwningPtr<ASTUnit> AST; AST.reset(new ASTUnit(false)); ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics=*/false); @@ -1571,33 +1511,35 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI, AST->Invocation = CI; AST->FileSystemOpts = CI->getFileSystemOpts(); AST->FileMgr = new FileManager(AST->FileSystemOpts); - AST->SourceMgr = new SourceManager(*Diags, *AST->FileMgr); + AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr); return AST.take(); } ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags, - ASTFrontendAction *Action) { + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + ASTFrontendAction *Action, + ASTUnit *Unit) { assert(CI && "A CompilerInvocation is required"); - // Create the AST unit. - llvm::OwningPtr<ASTUnit> AST; - AST.reset(new ASTUnit(false)); - ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics*/false); - AST->Diagnostics = Diags; + llvm::OwningPtr<ASTUnit> OwnAST; + ASTUnit *AST = Unit; + if (!AST) { + // Create the AST unit. + OwnAST.reset(create(CI, Diags)); + AST = OwnAST.get(); + } + AST->OnlyLocalDecls = false; AST->CaptureDiagnostics = false; - AST->CompleteTranslationUnit = Action ? Action->usesCompleteTranslationUnit() - : true; + AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete; AST->ShouldCacheCodeCompletionResults = false; - AST->Invocation = CI; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> - ASTUnitCleanup(AST.get()); - llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, - llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + ASTUnitCleanup(OwnAST.get()); + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.getPtr()); // We'll manage file buffers ourselves. @@ -1643,9 +1585,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, "IR inputs not supported here!"); // Configure the various subsystems. - AST->FileSystemOpts = Clang->getFileSystemOpts(); - AST->FileMgr = new FileManager(AST->FileSystemOpts); - AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr); AST->TheSema.reset(); AST->Ctx = 0; AST->PP = 0; @@ -1686,7 +1625,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, Act->EndSourceFile(); - return AST.take(); + if (OwnAST) + return OwnAST.take(); + else + return AST; } bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { @@ -1719,11 +1661,11 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { } ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags, + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags, bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble, - bool CompleteTranslationUnit, + TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool NestedMacroExpansions) { // Create the AST unit. @@ -1733,7 +1675,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, AST->Diagnostics = Diags; AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; - AST->CompleteTranslationUnit = CompleteTranslationUnit; + AST->TUKind = TUKind; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->Invocation = CI; AST->NestedMacroExpansions = NestedMacroExpansions; @@ -1741,8 +1683,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> ASTUnitCleanup(AST.get()); - llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, - llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.getPtr()); return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take(); @@ -1750,18 +1692,16 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, const char **ArgEnd, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags, - llvm::StringRef ResourceFilesPath, + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + StringRef ResourceFilesPath, bool OnlyLocalDecls, bool CaptureDiagnostics, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, bool RemappedFilesKeepOriginalName, bool PrecompilePreamble, - bool CompleteTranslationUnit, + TranslationUnitKind TUKind, bool CacheCodeCompletionResults, - bool CXXPrecompilePreamble, - bool CXXChainedPCH, bool NestedMacroExpansions) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object @@ -1771,17 +1711,18 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, ArgBegin); } - llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics; + SmallVector<StoredDiagnostic, 4> StoredDiagnostics; llvm::IntrusiveRefCntPtr<CompilerInvocation> CI; { + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, StoredDiagnostics); CI = clang::createInvocationFromCommandLine( - llvm::ArrayRef<const char *>(ArgBegin, ArgEnd-ArgBegin), - Diags); + llvm::makeArrayRef(ArgBegin, ArgEnd), + Diags); if (!CI) return 0; } @@ -1803,16 +1744,6 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, // Override the resources path. CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; - // Check whether we should precompile the preamble and/or use chained PCH. - // FIXME: This is a temporary hack while we debug C++ chained PCH. - if (CI->getLangOpts().CPlusPlus) { - PrecompilePreamble = PrecompilePreamble && CXXPrecompilePreamble; - - if (PrecompilePreamble && !CXXChainedPCH && - !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) - PrecompilePreamble = false; - } - // Create the AST unit. llvm::OwningPtr<ASTUnit> AST; AST.reset(new ASTUnit(false)); @@ -1823,10 +1754,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, AST->FileMgr = new FileManager(AST->FileSystemOpts); AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; - AST->CompleteTranslationUnit = CompleteTranslationUnit; + AST->TUKind = TUKind; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); - AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size(); AST->StoredDiagnostics.swap(StoredDiagnostics); AST->Invocation = CI; AST->NestedMacroExpansions = NestedMacroExpansions; @@ -1837,8 +1767,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation, llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> > CICleanup(CI.getPtr()); - llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, - llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.getPtr()); return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0 : AST.take(); @@ -1896,6 +1826,10 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { CurrentTopLevelHashValue != CompletionCacheTopLevelHashValue) CacheCodeCompletionResults(); + // We now need to clear out the completion allocator for + // clang_getCursorCompletionString; it'll be recreated if necessary. + CursorCompletionAllocator = 0; + return Result; } @@ -1985,7 +1919,7 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context, case CodeCompletionContext::CCC_Name: case CodeCompletionContext::CCC_PotentiallyQualifiedName: case CodeCompletionContext::CCC_ParenthesizedExpression: - case CodeCompletionContext::CCC_ObjCSuperclass: + case CodeCompletionContext::CCC_ObjCInterfaceName: break; case CodeCompletionContext::CCC_EnumTag: @@ -2052,12 +1986,11 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, bool AddedResult = false; unsigned InContexts = (Context.getKind() == CodeCompletionContext::CCC_Recovery? NormalContexts - : (1 << (Context.getKind() - 1))); - + : (1ULL << (Context.getKind() - 1))); // Contains the set of names that are hidden by "local" completion results. llvm::StringSet<llvm::BumpPtrAllocator> HiddenNames; typedef CodeCompletionResult Result; - llvm::SmallVector<Result, 8> AllResults; + SmallVector<Result, 8> AllResults; for (ASTUnit::cached_completion_iterator C = AST.cached_completion_begin(), CEnd = AST.cached_completion_end(); @@ -2139,22 +2072,22 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, -void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, +void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, bool IncludeMacros, bool IncludeCodePatterns, CodeCompleteConsumer &Consumer, - Diagnostic &Diag, LangOptions &LangOpts, + DiagnosticsEngine &Diag, LangOptions &LangOpts, SourceManager &SourceMgr, FileManager &FileMgr, - llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, - llvm::SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) { + SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, + SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) { if (!Invocation) return; SimpleTimer CompletionTimer(WantTiming); CompletionTimer.setOutput("Code completion @ " + File + ":" + - llvm::Twine(Line) + ":" + llvm::Twine(Column)); + Twine(Line) + ":" + Twine(Column)); llvm::IntrusiveRefCntPtr<CompilerInvocation> CCInvocation(new CompilerInvocation(*Invocation)); @@ -2252,7 +2185,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, llvm::sys::PathWithStatus MainPath(OriginalSourceFile); if (const FileStatus *CompleteFileStatus = CompleteFilePath.getFileStatus()) if (const FileStatus *MainStatus = MainPath.getFileStatus()) - if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID()) + if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID() && + Line > 1) OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*CCInvocation, false, Line - 1); @@ -2272,17 +2206,6 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, PreprocessorOpts.ImplicitPCHInclude = PreambleFile; PreprocessorOpts.DisablePCHValidation = true; - // The stored diagnostics have the old source manager. Copy them - // to our output set of stored diagnostics, updating the source - // manager to the one we were given. - for (unsigned I = NumStoredDiagnosticsFromDriver, - N = this->StoredDiagnostics.size(); - I < N; ++I) { - StoredDiagnostics.push_back(this->StoredDiagnostics[I]); - FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SourceMgr); - StoredDiagnostics[I].setLocation(Loc); - } - OwnedBuffers.push_back(OverrideMainBuffer); } else { PreprocessorOpts.PrecompiledPreambleBytes.first = 0; @@ -2296,36 +2219,58 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, Act.reset(new SyntaxOnlyAction); if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second, Clang->getFrontendOpts().Inputs[0].first)) { + if (OverrideMainBuffer) { + std::string ModName = PreambleFile; + TranslateStoredDiagnostics(Clang->getModuleManager(), ModName, + getSourceManager(), PreambleDiagnostics, + StoredDiagnostics); + } Act->Execute(); Act->EndSourceFile(); } } -CXSaveError ASTUnit::Save(llvm::StringRef File) { +CXSaveError ASTUnit::Save(StringRef File) { if (getDiagnostics().hasUnrecoverableErrorOccurred()) return CXSaveError_TranslationErrors; - + + // Write to a temporary file and later rename it to the actual file, to avoid + // possible race conditions. + llvm::SmallString<128> TempPath; + TempPath = File; + TempPath += "-%%%%%%%%"; + int fd; + if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath, + /*makeAbsolute=*/false)) + return CXSaveError_Unknown; + // FIXME: Can we somehow regenerate the stat cache here, or do we need to // unconditionally create a stat cache when we parse the file? - std::string ErrorInfo; - llvm::raw_fd_ostream Out(File.str().c_str(), ErrorInfo, - llvm::raw_fd_ostream::F_Binary); - if (!ErrorInfo.empty() || Out.has_error()) - return CXSaveError_Unknown; + llvm::raw_fd_ostream Out(fd, /*shouldClose=*/true); serialize(Out); Out.close(); - return Out.has_error()? CXSaveError_Unknown : CXSaveError_None; + if (Out.has_error()) + return CXSaveError_Unknown; + + if (llvm::error_code ec = llvm::sys::fs::rename(TempPath.str(), File)) { + bool exists; + llvm::sys::fs::remove(TempPath.str(), exists); + return CXSaveError_Unknown; + } + + return CXSaveError_None; } -bool ASTUnit::serialize(llvm::raw_ostream &OS) { +bool ASTUnit::serialize(raw_ostream &OS) { if (getDiagnostics().hasErrorOccurred()) return true; std::vector<unsigned char> Buffer; llvm::BitstreamWriter Stream(Buffer); ASTWriter Writer(Stream); - Writer.WriteAST(getSema(), 0, std::string(), 0); + // FIXME: Handle modules + Writer.WriteAST(getSema(), 0, std::string(), /*IsModule=*/false, ""); // Write the generated bitstream to "Out". if (!Buffer.empty()) @@ -2333,3 +2278,168 @@ bool ASTUnit::serialize(llvm::raw_ostream &OS) { return false; } + +typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap; + +static void TranslateSLoc(SourceLocation &L, SLocRemap &Remap) { + unsigned Raw = L.getRawEncoding(); + const unsigned MacroBit = 1U << 31; + L = SourceLocation::getFromRawEncoding((Raw & MacroBit) | + ((Raw & ~MacroBit) + Remap.find(Raw & ~MacroBit)->second)); +} + +void ASTUnit::TranslateStoredDiagnostics( + ASTReader *MMan, + StringRef ModName, + SourceManager &SrcMgr, + const SmallVectorImpl<StoredDiagnostic> &Diags, + SmallVectorImpl<StoredDiagnostic> &Out) { + // The stored diagnostic has the old source manager in it; update + // the locations to refer into the new source manager. We also need to remap + // all the locations to the new view. This includes the diag location, any + // associated source ranges, and the source ranges of associated fix-its. + // FIXME: There should be a cleaner way to do this. + + SmallVector<StoredDiagnostic, 4> Result; + Result.reserve(Diags.size()); + assert(MMan && "Don't have a module manager"); + serialization::Module *Mod = MMan->ModuleMgr.lookup(ModName); + assert(Mod && "Don't have preamble module"); + SLocRemap &Remap = Mod->SLocRemap; + for (unsigned I = 0, N = Diags.size(); I != N; ++I) { + // Rebuild the StoredDiagnostic. + const StoredDiagnostic &SD = Diags[I]; + SourceLocation L = SD.getLocation(); + TranslateSLoc(L, Remap); + FullSourceLoc Loc(L, SrcMgr); + + SmallVector<CharSourceRange, 4> Ranges; + Ranges.reserve(SD.range_size()); + for (StoredDiagnostic::range_iterator I = SD.range_begin(), + E = SD.range_end(); + I != E; ++I) { + SourceLocation BL = I->getBegin(); + TranslateSLoc(BL, Remap); + SourceLocation EL = I->getEnd(); + TranslateSLoc(EL, Remap); + Ranges.push_back(CharSourceRange(SourceRange(BL, EL), I->isTokenRange())); + } + + SmallVector<FixItHint, 2> FixIts; + FixIts.reserve(SD.fixit_size()); + for (StoredDiagnostic::fixit_iterator I = SD.fixit_begin(), + E = SD.fixit_end(); + I != E; ++I) { + FixIts.push_back(FixItHint()); + FixItHint &FH = FixIts.back(); + FH.CodeToInsert = I->CodeToInsert; + SourceLocation BL = I->RemoveRange.getBegin(); + TranslateSLoc(BL, Remap); + SourceLocation EL = I->RemoveRange.getEnd(); + TranslateSLoc(EL, Remap); + FH.RemoveRange = CharSourceRange(SourceRange(BL, EL), + I->RemoveRange.isTokenRange()); + } + + Result.push_back(StoredDiagnostic(SD.getLevel(), SD.getID(), + SD.getMessage(), Loc, Ranges, FixIts)); + } + Result.swap(Out); +} + +SourceLocation ASTUnit::getLocation(const FileEntry *File, + unsigned Line, unsigned Col) const { + const SourceManager &SM = getSourceManager(); + SourceLocation Loc = SM.translateFileLineCol(File, Line, Col); + return SM.getMacroArgExpandedLocation(Loc); +} + +SourceLocation ASTUnit::getLocation(const FileEntry *File, + unsigned Offset) const { + const SourceManager &SM = getSourceManager(); + SourceLocation FileLoc = SM.translateFileLineCol(File, 1, 1); + return SM.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Offset)); +} + +/// \brief If \arg Loc is a loaded location from the preamble, returns +/// the corresponding local location of the main file, otherwise it returns +/// \arg Loc. +SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) { + FileID PreambleID; + if (SourceMgr) + PreambleID = SourceMgr->getPreambleFileID(); + + if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) + return Loc; + + unsigned Offs; + if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) { + SourceLocation FileLoc + = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID()); + return FileLoc.getLocWithOffset(Offs); + } + + return Loc; +} + +/// \brief If \arg Loc is a local location of the main file but inside the +/// preamble chunk, returns the corresponding loaded location from the +/// preamble, otherwise it returns \arg Loc. +SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) { + FileID PreambleID; + if (SourceMgr) + PreambleID = SourceMgr->getPreambleFileID(); + + if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) + return Loc; + + unsigned Offs; + if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) && + Offs < Preamble.size()) { + SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID); + return FileLoc.getLocWithOffset(Offs); + } + + return Loc; +} + +void ASTUnit::PreambleData::countLines() const { + NumLines = 0; + if (empty()) + return; + + for (std::vector<char>::const_iterator + I = Buffer.begin(), E = Buffer.end(); I != E; ++I) { + if (*I == '\n') + ++NumLines; + } + if (Buffer.back() != '\n') + ++NumLines; +} + +#ifndef NDEBUG +ASTUnit::ConcurrencyState::ConcurrencyState() { + Mutex = new llvm::sys::MutexImpl(/*recursive=*/true); +} + +ASTUnit::ConcurrencyState::~ConcurrencyState() { + delete static_cast<llvm::sys::MutexImpl *>(Mutex); +} + +void ASTUnit::ConcurrencyState::start() { + bool acquired = static_cast<llvm::sys::MutexImpl *>(Mutex)->tryacquire(); + assert(acquired && "Concurrent access to ASTUnit!"); +} + +void ASTUnit::ConcurrencyState::finish() { + static_cast<llvm::sys::MutexImpl *>(Mutex)->release(); +} + +#else // NDEBUG + +ASTUnit::ConcurrencyState::ConcurrencyState() {} +ASTUnit::ConcurrencyState::~ConcurrencyState() {} +void ASTUnit::ConcurrencyState::start() {} +void ASTUnit::ConcurrencyState::finish() {} + +#endif diff --git a/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp index 20b5189..8195445 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp @@ -71,13 +71,13 @@ public: bool isFile() const { return Kind == IsFE; } - llvm::StringRef getString() const { + StringRef getString() const { return Kind == IsFE ? FE->getName() : Path; } unsigned getKind() const { return (unsigned) Kind; } - void EmitData(llvm::raw_ostream& Out) { + void EmitData(raw_ostream& Out) { switch (Kind) { case IsFE: // Emit stat information. @@ -119,7 +119,7 @@ public: } static std::pair<unsigned,unsigned> - EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V, + EmitKeyDataLength(raw_ostream& Out, PTHEntryKeyVariant V, const PTHEntry& E) { unsigned n = V.getString().size() + 1 + 1; @@ -131,14 +131,14 @@ public: return std::make_pair(n, m); } - static void EmitKey(llvm::raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){ + static void EmitKey(raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){ // Emit the entry kind. ::Emit8(Out, (unsigned) V.getKind()); // Emit the string. Out.write(V.getString().data(), n - 1); } - static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V, + static void EmitData(raw_ostream& Out, PTHEntryKeyVariant V, const PTHEntry& E, unsigned) { @@ -197,7 +197,7 @@ class PTHWriter { Out.write(Ptr, NumBytes); } - void EmitString(llvm::StringRef V) { + void EmitString(StringRef V) { ::Emit16(Out, V.size()); EmitBuf(V.data(), V.size()); } @@ -247,7 +247,7 @@ void PTHWriter::EmitToken(const Token& T) { } else { // We cache *un-cleaned* spellings. This gives us 100% fidelity with the // source code. - llvm::StringRef s(T.getLiteralData(), T.getLength()); + StringRef s(T.getLiteralData(), T.getLength()); // Get the string entry. llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s); @@ -584,20 +584,20 @@ public: } static std::pair<unsigned,unsigned> - EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) { + EmitKeyDataLength(raw_ostream& Out, const PTHIdKey* key, uint32_t) { unsigned n = key->II->getLength() + 1; ::Emit16(Out, n); return std::make_pair(n, sizeof(uint32_t)); } - static void EmitKey(llvm::raw_ostream& Out, PTHIdKey* key, unsigned n) { + static void EmitKey(raw_ostream& Out, PTHIdKey* key, unsigned n) { // Record the location of the key data. This is used when generating // the mapping from persistent IDs to strings. key->FileOffset = Out.tell(); Out.write(key->II->getNameStart(), n); } - static void EmitData(llvm::raw_ostream& Out, PTHIdKey*, uint32_t pID, + static void EmitData(raw_ostream& Out, PTHIdKey*, uint32_t pID, unsigned) { ::Emit32(Out, pID); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp index c58e3af..5526487 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp @@ -19,12 +19,13 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PTHManager.h" -#include "clang/Frontend/ChainedDiagnosticClient.h" +#include "clang/Frontend/ChainedDiagnosticConsumer.h" #include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/LogDiagnosticPrinter.h" #include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/VerifyDiagnosticConsumer.h" #include "clang/Frontend/Utils.h" #include "clang/Serialization/ASTReader.h" #include "clang/Sema/CodeCompleteConsumer.h" @@ -38,11 +39,25 @@ #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/system_error.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Config/config.h" + +// Support for FileLockManager +#include <fstream> +#include <sys/types.h> +#include <sys/stat.h> + +#if LLVM_ON_WIN32 +#include <windows.h> +#endif +#if LLVM_ON_UNIX +#include <unistd.h> +#endif + using namespace clang; CompilerInstance::CompilerInstance() - : Invocation(new CompilerInvocation()) { + : Invocation(new CompilerInvocation()), ModuleManager(0) { } CompilerInstance::~CompilerInstance() { @@ -52,7 +67,7 @@ void CompilerInstance::setInvocation(CompilerInvocation *Value) { Invocation = Value; } -void CompilerInstance::setDiagnostics(Diagnostic *Value) { +void CompilerInstance::setDiagnostics(DiagnosticsEngine *Value) { Diagnostics = Value; } @@ -64,7 +79,7 @@ void CompilerInstance::setFileManager(FileManager *Value) { FileMgr = Value; } -void CompilerInstance::setSourceManager(SourceManager *Value) { +void CompilerInstance::setSourceManager(SourceManager *Value) { SourceMgr = Value; } @@ -87,9 +102,9 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { // Diagnostics static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, unsigned argc, const char* const *argv, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { std::string ErrorInfo; - llvm::OwningPtr<llvm::raw_ostream> OS( + llvm::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) @@ -103,17 +118,17 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, (*OS) << '\n'; // Chain in a diagnostic client which will log the diagnostics. - DiagnosticClient *Logger = + DiagnosticConsumer *Logger = new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true); - Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger)); + Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger)); } static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts, const CodeGenOptions *CodeGenOpts, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { std::string ErrorInfo; bool OwnsStream = false; - llvm::raw_ostream *OS = &llvm::errs(); + raw_ostream *OS = &llvm::errs(); if (DiagOpts.DiagnosticLogFile != "-") { // Create the output stream. llvm::raw_fd_ostream *FileOS( @@ -135,38 +150,47 @@ static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts, OwnsStream); if (CodeGenOpts) Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags); - Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger)); + Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger)); } void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv, - DiagnosticClient *Client) { + DiagnosticConsumer *Client, + bool ShouldOwnClient, + bool ShouldCloneClient) { Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client, + ShouldOwnClient, ShouldCloneClient, &getCodeGenOpts()); } -llvm::IntrusiveRefCntPtr<Diagnostic> +llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, int Argc, const char* const *Argv, - DiagnosticClient *Client, + DiagnosticConsumer *Client, + bool ShouldOwnClient, + bool ShouldCloneClient, const CodeGenOptions *CodeGenOpts) { llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID)); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> + Diags(new DiagnosticsEngine(DiagID)); // Create the diagnostic client for reporting errors or for // implementing -verify. - if (Client) - Diags->setClient(Client); - else + if (Client) { + if (ShouldCloneClient) + Diags->setClient(Client->clone(*Diags), ShouldOwnClient); + else + Diags->setClient(Client, ShouldOwnClient); + } else Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); // Chain in -verify checker, if requested. if (Opts.VerifyDiagnostics) - Diags->setClient(new VerifyDiagnosticsClient(*Diags, Diags->takeClient())); + Diags->setClient(new VerifyDiagnosticConsumer(*Diags)); // Chain in -diagnostic-log-file dumper, if requested. if (!Opts.DiagnosticLogFile.empty()) SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags); - + if (!Opts.DumpBuildInformation.empty()) SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); @@ -191,49 +215,47 @@ void CompilerInstance::createSourceManager(FileManager &FileMgr) { // Preprocessor void CompilerInstance::createPreprocessor() { - PP = createPreprocessor(getDiagnostics(), getLangOpts(), - getPreprocessorOpts(), getHeaderSearchOpts(), - getDependencyOutputOpts(), getTarget(), - getFrontendOpts(), getSourceManager(), - getFileManager()); -} - -Preprocessor * -CompilerInstance::createPreprocessor(Diagnostic &Diags, - const LangOptions &LangInfo, - const PreprocessorOptions &PPOpts, - const HeaderSearchOptions &HSOpts, - const DependencyOutputOptions &DepOpts, - const TargetInfo &Target, - const FrontendOptions &FEOpts, - SourceManager &SourceMgr, - FileManager &FileMgr) { + const PreprocessorOptions &PPOpts = getPreprocessorOpts(); + // Create a PTH manager if we are using some form of a token cache. PTHManager *PTHMgr = 0; if (!PPOpts.TokenCache.empty()) - PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); + PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics()); // Create the Preprocessor. - HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); - Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, - SourceMgr, *HeaderInfo, PTHMgr, - /*OwnsHeaderSearch=*/true); + HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager()); + PP = new Preprocessor(getDiagnostics(), getLangOpts(), &getTarget(), + getSourceManager(), *HeaderInfo, *this, PTHMgr, + /*OwnsHeaderSearch=*/true); // Note that this is different then passing PTHMgr to Preprocessor's ctor. // That argument is used as the IdentifierInfoLookup argument to // IdentifierTable's ctor. if (PTHMgr) { - PTHMgr->setPreprocessor(PP); + PTHMgr->setPreprocessor(&*PP); PP->setPTHManager(PTHMgr); } if (PPOpts.DetailedRecord) PP->createPreprocessingRecord( - PPOpts.DetailedRecordIncludesNestedMacroExpansions); - - InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); + PPOpts.DetailedRecordIncludesNestedMacroExpansions); + + InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts()); + + // Set up the module path, including the hash for the + // module-creation options. + llvm::SmallString<256> SpecificModuleCache( + getHeaderSearchOpts().ModuleCachePath); + if (!getHeaderSearchOpts().DisableModuleHash) + llvm::sys::path::append(SpecificModuleCache, + getInvocation().getModuleHash()); + PP->getHeaderSearchInfo().configureModules(SpecificModuleCache, + getPreprocessorOpts().ModuleBuildPath.empty() + ? std::string() + : getPreprocessorOpts().ModuleBuildPath.back()); // Handle generating dependencies, if requested. + const DependencyOutputOptions &DepOpts = getDependencyOutputOpts(); if (!DepOpts.OutputFile.empty()) AttachDependencyFileGen(*PP, DepOpts); @@ -241,14 +263,12 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, if (DepOpts.ShowHeaderIncludes) AttachHeaderIncludeGen(*PP); if (!DepOpts.HeaderIncludeOutputFile.empty()) { - llvm::StringRef OutputPath = DepOpts.HeaderIncludeOutputFile; + StringRef OutputPath = DepOpts.HeaderIncludeOutputFile; if (OutputPath == "-") OutputPath = ""; AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath, /*ShowDepth=*/false); } - - return PP; } // ASTContext @@ -256,30 +276,31 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, void CompilerInstance::createASTContext() { Preprocessor &PP = getPreprocessor(); Context = new ASTContext(getLangOpts(), PP.getSourceManager(), - getTarget(), PP.getIdentifierTable(), + &getTarget(), PP.getIdentifierTable(), PP.getSelectorTable(), PP.getBuiltinInfo(), /*size_reserve=*/ 0); } // ExternalASTSource -void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, +void CompilerInstance::createPCHExternalASTSource(StringRef Path, bool DisablePCHValidation, bool DisableStatCache, void *DeserializationListener){ llvm::OwningPtr<ExternalASTSource> Source; bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, - DisablePCHValidation, + DisablePCHValidation, DisableStatCache, getPreprocessor(), getASTContext(), DeserializationListener, Preamble)); + ModuleManager = static_cast<ASTReader*>(Source.get()); getASTContext().setExternalSource(Source); } ExternalASTSource * -CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, +CompilerInstance::createPCHExternalASTSource(StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, bool DisableStatCache, @@ -288,14 +309,15 @@ CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, void *DeserializationListener, bool Preamble) { llvm::OwningPtr<ASTReader> Reader; - Reader.reset(new ASTReader(PP, &Context, - Sysroot.empty() ? 0 : Sysroot.c_str(), + Reader.reset(new ASTReader(PP, Context, + Sysroot.empty() ? "" : Sysroot.c_str(), DisablePCHValidation, DisableStatCache)); Reader->setDeserializationListener( static_cast<ASTDeserializationListener *>(DeserializationListener)); switch (Reader->ReadAST(Path, - Preamble ? ASTReader::Preamble : ASTReader::PCH)) { + Preamble ? serialization::MK_Preamble + : serialization::MK_PCH)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. @@ -316,7 +338,7 @@ CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, // Code Completion -static bool EnableCodeCompletion(Preprocessor &PP, +static bool EnableCodeCompletion(Preprocessor &PP, const std::string &Filename, unsigned Line, unsigned Column) { @@ -371,19 +393,19 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, bool ShowMacros, bool ShowCodePatterns, bool ShowGlobals, - llvm::raw_ostream &OS) { + raw_ostream &OS) { if (EnableCodeCompletion(PP, Filename, Line, Column)) return 0; // Set up the creation routine for code-completion. - return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, + return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, ShowGlobals, OS); } -void CompilerInstance::createSema(bool CompleteTranslationUnit, +void CompilerInstance::createSema(TranslationUnitKind TUKind, CodeCompleteConsumer *CompletionConsumer) { TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(), - CompleteTranslationUnit, CompletionConsumer)); + TUKind, CompletionConsumer)); } // Output Files @@ -418,28 +440,30 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) { } } else if (!it->Filename.empty() && EraseFiles) llvm::sys::Path(it->Filename).eraseFromDisk(); - + } OutputFiles.clear(); } llvm::raw_fd_ostream * CompilerInstance::createDefaultOutputFile(bool Binary, - llvm::StringRef InFile, - llvm::StringRef Extension) { + StringRef InFile, + StringRef Extension) { return createOutputFile(getFrontendOpts().OutputFile, Binary, /*RemoveFileOnSignal=*/true, InFile, Extension); } llvm::raw_fd_ostream * -CompilerInstance::createOutputFile(llvm::StringRef OutputPath, +CompilerInstance::createOutputFile(StringRef OutputPath, bool Binary, bool RemoveFileOnSignal, - llvm::StringRef InFile, - llvm::StringRef Extension) { + StringRef InFile, + StringRef Extension, + bool UseTemporary) { std::string Error, OutputPathName, TempPathName; llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, RemoveFileOnSignal, InFile, Extension, + UseTemporary, &OutputPathName, &TempPathName); if (!OS) { @@ -457,12 +481,13 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, } llvm::raw_fd_ostream * -CompilerInstance::createOutputFile(llvm::StringRef OutputPath, +CompilerInstance::createOutputFile(StringRef OutputPath, std::string &Error, bool Binary, bool RemoveFileOnSignal, - llvm::StringRef InFile, - llvm::StringRef Extension, + StringRef InFile, + StringRef Extension, + bool UseTemporary, std::string *ResultPathName, std::string *TempPathName) { std::string OutFile, TempFile; @@ -478,8 +503,11 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, } else { OutFile = "-"; } - - if (OutFile != "-") { + + llvm::OwningPtr<llvm::raw_fd_ostream> OS; + std::string OSFile; + + if (UseTemporary && OutFile != "-") { llvm::sys::Path OutPath(OutFile); // Only create the temporary if we can actually write to OutPath, otherwise // we want to fail early. @@ -487,21 +515,26 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, if ((llvm::sys::fs::exists(OutPath.str(), Exists) || !Exists) || (OutPath.isRegularFile() && OutPath.canWrite())) { // Create a temporary file. - llvm::sys::Path TempPath(OutFile); - if (!TempPath.createTemporaryFileOnDisk()) - TempFile = TempPath.str(); + llvm::SmallString<128> TempPath; + TempPath = OutFile; + TempPath += "-%%%%%%%%"; + int fd; + if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath, + /*makeAbsolute=*/false) == llvm::errc::success) { + OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true)); + OSFile = TempFile = TempPath.str(); + } } } - std::string OSFile = OutFile; - if (!TempFile.empty()) - OSFile = TempFile; - - llvm::OwningPtr<llvm::raw_fd_ostream> OS( - new llvm::raw_fd_ostream(OSFile.c_str(), Error, - (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); - if (!Error.empty()) - return 0; + if (!OS) { + OSFile = OutFile; + OS.reset( + new llvm::raw_fd_ostream(OSFile.c_str(), Error, + (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); + if (!Error.empty()) + return 0; + } // Make sure the out stream file gets removed if we crash. if (RemoveFileOnSignal) @@ -517,21 +550,18 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, // Initialization Utilities -bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { +bool CompilerInstance::InitializeSourceManager(StringRef InputFile) { return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), getSourceManager(), getFrontendOpts()); } -bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, - Diagnostic &Diags, +bool CompilerInstance::InitializeSourceManager(StringRef InputFile, + DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { - // Figure out where to get and map in the main file, unless it's already - // been created (e.g., by a precompiled preamble). - if (!SourceMgr.getMainFileID().isInvalid()) { - // Do nothing: the main file has already been set. - } else if (InputFile != "-") { + // Figure out where to get and map in the main file. + if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; @@ -565,7 +595,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // FIXME: Take this as an argument, once all the APIs we used have moved to // taking it as an input instead of hard-coding llvm::errs. - llvm::raw_ostream &OS = llvm::errs(); + raw_ostream &OS = llvm::errs(); // Create the target instance. setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); @@ -589,7 +619,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { if (getFrontendOpts().ShowStats) llvm::EnableStatistics(); - + for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { const std::string &InFile = getFrontendOpts().Inputs[i].second; @@ -608,7 +638,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { // Get the total number of warnings/errors from the client. unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings(); unsigned NumErrors = getDiagnostics().getClient()->getNumErrors(); - + if (NumWarnings) OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s"); if (NumWarnings && NumErrors) @@ -627,4 +657,456 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { return !getDiagnostics().getClient()->getNumErrors(); } +/// \brief Determine the appropriate source input kind based on language +/// options. +static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) { + if (LangOpts.OpenCL) + return IK_OpenCL; + if (LangOpts.CUDA) + return IK_CUDA; + if (LangOpts.ObjC1) + return LangOpts.CPlusPlus? IK_ObjCXX : IK_ObjC; + return LangOpts.CPlusPlus? IK_CXX : IK_C; +} + +namespace { + struct CompileModuleData { + CompilerInstance &Instance; + GeneratePCHAction &CreateModuleAction; + }; +} + +/// \brief Helper function that executes the module-generating action under +/// a crash recovery context. +static void doCompileModule(void *UserData) { + CompileModuleData &Data = *reinterpret_cast<CompileModuleData *>(UserData); + Data.Instance.ExecuteAction(Data.CreateModuleAction); +} + +namespace { + /// \brief Class that manages the creation of a lock file to aid + /// implicit coordination between different processes. + /// + /// The implicit coordination works by creating a ".lock" file alongside + /// the file that we're coordinating for, using the atomicity of the file + /// system to ensure that only a single process can create that ".lock" file. + /// When the lock file is removed, the owning process has finished the + /// operation. + class LockFileManager { + public: + /// \brief Describes the state of a lock file. + enum LockFileState { + /// \brief The lock file has been created and is owned by this instance + /// of the object. + LFS_Owned, + /// \brief The lock file already exists and is owned by some other + /// instance. + LFS_Shared, + /// \brief An error occurred while trying to create or find the lock + /// file. + LFS_Error + }; + + private: + llvm::SmallString<128> LockFileName; + llvm::SmallString<128> UniqueLockFileName; + + llvm::Optional<std::pair<std::string, int> > Owner; + llvm::Optional<llvm::error_code> Error; + + LockFileManager(const LockFileManager &); + LockFileManager &operator=(const LockFileManager &); + + static llvm::Optional<std::pair<std::string, int> > + readLockFile(StringRef LockFileName); + + static bool processStillExecuting(StringRef Hostname, int PID); + + public: + + LockFileManager(StringRef FileName); + ~LockFileManager(); + + /// \brief Determine the state of the lock file. + LockFileState getState() const; + + operator LockFileState() const { return getState(); } + + /// \brief For a shared lock, wait until the owner releases the lock. + void waitForUnlock(); + }; +} + +/// \brief Attempt to read the lock file with the given name, if it exists. +/// +/// \param LockFileName The name of the lock file to read. +/// +/// \returns The process ID of the process that owns this lock file +llvm::Optional<std::pair<std::string, int> > +LockFileManager::readLockFile(StringRef LockFileName) { + // Check whether the lock file exists. If not, clearly there's nothing + // to read, so we just return. + bool Exists = false; + if (llvm::sys::fs::exists(LockFileName, Exists) || !Exists) + return llvm::Optional<std::pair<std::string, int> >(); + + // Read the owning host and PID out of the lock file. If it appears that the + // owning process is dead, the lock file is invalid. + int PID = 0; + std::string Hostname; + std::ifstream Input(LockFileName.str().c_str()); + if (Input >> Hostname >> PID && PID > 0 && + processStillExecuting(Hostname, PID)) + return std::make_pair(Hostname, PID); + + // Delete the lock file. It's invalid anyway. + bool Existed; + llvm::sys::fs::remove(LockFileName, Existed); + return llvm::Optional<std::pair<std::string, int> >(); +} + +bool LockFileManager::processStillExecuting(StringRef Hostname, int PID) { +#if LLVM_ON_UNIX + char MyHostname[256]; + MyHostname[255] = 0; + MyHostname[0] = 0; + gethostname(MyHostname, 255); + // Check whether the process is dead. If so, we're done. + if (MyHostname == Hostname && getsid(PID) == -1 && errno == ESRCH) + return false; +#endif + + return true; +} + +LockFileManager::LockFileManager(StringRef FileName) +{ + LockFileName = FileName; + LockFileName += ".lock"; + + // If the lock file already exists, don't bother to try to create our own + // lock file; it won't work anyway. Just figure out who owns this lock file. + if ((Owner = readLockFile(LockFileName))) + return; + + // Create a lock file that is unique to this instance. + UniqueLockFileName = LockFileName; + UniqueLockFileName += "-%%%%%%%%"; + int UniqueLockFileID; + if (llvm::error_code EC + = llvm::sys::fs::unique_file(UniqueLockFileName.str(), + UniqueLockFileID, + UniqueLockFileName, + /*makeAbsolute=*/false)) { + Error = EC; + return; + } + + // Write our process ID to our unique lock file. + { + llvm::raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true); + +#if LLVM_ON_UNIX + // FIXME: move getpid() call into LLVM + char hostname[256]; + hostname[255] = 0; + hostname[0] = 0; + gethostname(hostname, 255); + Out << hostname << ' ' << getpid(); +#else + Out << "localhost 1"; +#endif + Out.close(); + + if (Out.has_error()) { + // We failed to write out PID, so make up an excuse, remove the + // unique lock file, and fail. + Error = llvm::make_error_code(llvm::errc::no_space_on_device); + bool Existed; + llvm::sys::fs::remove(UniqueLockFileName.c_str(), Existed); + return; + } + } + + // Create a hard link from the lock file name. If this succeeds, we're done. + llvm::error_code EC + = llvm::sys::fs::create_hard_link(UniqueLockFileName.str(), + LockFileName.str()); + if (EC == llvm::errc::success) + return; + + // Creating the hard link failed. + +#ifdef LLVM_ON_UNIX + // The creation of the hard link may appear to fail, but if stat'ing the + // unique file returns a link count of 2, then we can still declare success. + struct stat StatBuf; + if (stat(UniqueLockFileName.c_str(), &StatBuf) == 0 && + StatBuf.st_nlink == 2) + return; +#endif + + // Someone else managed to create the lock file first. Wipe out our unique + // lock file (it's useless now) and read the process ID from the lock file. + bool Existed; + llvm::sys::fs::remove(UniqueLockFileName.str(), Existed); + if ((Owner = readLockFile(LockFileName))) + return; + + // There is a lock file that nobody owns; try to clean it up and report + // an error. + llvm::sys::fs::remove(LockFileName.str(), Existed); + Error = EC; +} + +LockFileManager::LockFileState LockFileManager::getState() const { + if (Owner) + return LFS_Shared; + + if (Error) + return LFS_Error; + + return LFS_Owned; +} + +LockFileManager::~LockFileManager() { + if (getState() != LFS_Owned) + return; + + // Since we own the lock, remove the lock file and our own unique lock file. + bool Existed; + llvm::sys::fs::remove(LockFileName.str(), Existed); + llvm::sys::fs::remove(UniqueLockFileName.str(), Existed); +} + +void LockFileManager::waitForUnlock() { + if (getState() != LFS_Shared) + return; + +#if LLVM_ON_WIN32 + unsigned long Interval = 1; +#else + struct timespec Interval; + Interval.tv_sec = 0; + Interval.tv_nsec = 1000000; +#endif + // Don't wait more than an hour for the file to appear. + const unsigned MaxSeconds = 3600; + do { + // Sleep for the designated interval, to allow the owning process time to + // finish up and + // FIXME: Should we hook in to system APIs to get a notification when the + // lock file is deleted? +#if LLVM_ON_WIN32 + Sleep(Interval); +#else + nanosleep(&Interval, NULL); +#endif + // If the file no longer exists, we're done. + bool Exists = false; + if (!llvm::sys::fs::exists(LockFileName.str(), Exists) && !Exists) + return; + + if (!processStillExecuting((*Owner).first, (*Owner).second)) + return; + + // Exponentially increase the time we wait for the lock to be removed. +#if LLVM_ON_WIN32 + Interval *= 2; +#else + Interval.tv_sec *= 2; + Interval.tv_nsec *= 2; + if (Interval.tv_nsec >= 1000000000) { + ++Interval.tv_sec; + Interval.tv_nsec -= 1000000000; + } +#endif + } while ( +#if LLVM_ON_WIN32 + Interval < MaxSeconds * 1000 +#else + Interval.tv_sec < (time_t)MaxSeconds +#endif + ); + + // Give up. +} + +/// \brief Compile a module file for the given module name with the given +/// umbrella header, using the options provided by the importing compiler +/// instance. +static void compileModule(CompilerInstance &ImportingInstance, + StringRef ModuleName, + StringRef ModuleFileName, + StringRef UmbrellaHeader) { + LockFileManager Locked(ModuleFileName); + switch (Locked) { + case LockFileManager::LFS_Error: + return; + + case LockFileManager::LFS_Owned: + // We're responsible for building the module ourselves. Do so below. + break; + + case LockFileManager::LFS_Shared: + // Someone else is responsible for building the module. Wait for them to + // finish. + Locked.waitForUnlock(); + break; + } + + // Construct a compiler invocation for creating this module. + llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation + (new CompilerInvocation(ImportingInstance.getInvocation())); + + // For any options that aren't intended to affect how a module is built, + // reset them to their default values. + Invocation->getLangOpts().resetNonModularOptions(); + Invocation->getPreprocessorOpts().resetNonModularOptions(); + + // Note that this module is part of the module build path, so that we + // can detect cycles in the module graph. + Invocation->getPreprocessorOpts().ModuleBuildPath.push_back(ModuleName); + + // Set up the inputs/outputs so that we build the module from its umbrella + // header. + FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); + FrontendOpts.OutputFile = ModuleFileName.str(); + FrontendOpts.DisableFree = false; + FrontendOpts.Inputs.clear(); + FrontendOpts.Inputs.push_back( + std::make_pair(getSourceInputKindFromOptions(Invocation->getLangOpts()), + UmbrellaHeader)); + + Invocation->getDiagnosticOpts().VerifyDiagnostics = 0; + + + assert(ImportingInstance.getInvocation().getModuleHash() == + Invocation->getModuleHash() && "Module hash mismatch!"); + + // Construct a compiler instance that will be used to actually create the + // module. + CompilerInstance Instance; + Instance.setInvocation(&*Invocation); + Instance.createDiagnostics(/*argc=*/0, /*argv=*/0, + &ImportingInstance.getDiagnosticClient(), + /*ShouldOwnClient=*/true, + /*ShouldCloneClient=*/true); + + // Construct a module-generating action. + GeneratePCHAction CreateModuleAction(true); + + // Execute the action to actually build the module in-place. Use a separate + // thread so that we get a stack large enough. + const unsigned ThreadStackSize = 8 << 20; + llvm::CrashRecoveryContext CRC; + CompileModuleData Data = { Instance, CreateModuleAction }; + CRC.RunSafelyOnThread(&doCompileModule, &Data, ThreadStackSize); +} + +ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc, + IdentifierInfo &ModuleName, + SourceLocation ModuleNameLoc) { + // Determine what file we're searching from. + SourceManager &SourceMgr = getSourceManager(); + SourceLocation ExpandedImportLoc = SourceMgr.getExpansionLoc(ImportLoc); + const FileEntry *CurFile + = SourceMgr.getFileEntryForID(SourceMgr.getFileID(ExpandedImportLoc)); + if (!CurFile) + CurFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()); + + // Search for a module with the given name. + std::string UmbrellaHeader; + std::string ModuleFileName; + const FileEntry *ModuleFile + = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName(), + &ModuleFileName, + &UmbrellaHeader); + + bool BuildingModule = false; + if (!ModuleFile && !UmbrellaHeader.empty()) { + // We didn't find the module, but there is an umbrella header that + // can be used to create the module file. Create a separate compilation + // module to do so. + + // 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.getName()); + if (Pos != ModuleBuildPath.end()) { + llvm::SmallString<256> CyclePath; + for (; Pos != ModuleBuildPath.end(); ++Pos) { + CyclePath += *Pos; + CyclePath += " -> "; + } + CyclePath += ModuleName.getName(); + + getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle) + << ModuleName.getName() << CyclePath; + return 0; + } + + getDiagnostics().Report(ModuleNameLoc, diag::warn_module_build) + << ModuleName.getName(); + BuildingModule = true; + compileModule(*this, ModuleName.getName(), ModuleFileName, UmbrellaHeader); + ModuleFile = PP->getHeaderSearchInfo().lookupModule(ModuleName.getName()); + } + + if (!ModuleFile) { + getDiagnostics().Report(ModuleNameLoc, + BuildingModule? diag::err_module_not_built + : diag::err_module_not_found) + << ModuleName.getName() + << SourceRange(ImportLoc, ModuleNameLoc); + return 0; + } + + // If we don't already have an ASTReader, create one now. + if (!ModuleManager) { + if (!hasASTContext()) + createASTContext(); + + std::string Sysroot = getHeaderSearchOpts().Sysroot; + const PreprocessorOptions &PPOpts = getPreprocessorOpts(); + ModuleManager = new ASTReader(getPreprocessor(), *Context, + Sysroot.empty() ? "" : Sysroot.c_str(), + PPOpts.DisablePCHValidation, + PPOpts.DisableStatCache); + if (hasASTConsumer()) { + ModuleManager->setDeserializationListener( + getASTConsumer().GetASTDeserializationListener()); + getASTContext().setASTMutationListener( + getASTConsumer().GetASTMutationListener()); + } + llvm::OwningPtr<ExternalASTSource> Source; + Source.reset(ModuleManager); + getASTContext().setExternalSource(Source); + if (hasSema()) + ModuleManager->InitializeSema(getSema()); + if (hasASTConsumer()) + ModuleManager->StartTranslationUnit(&getASTConsumer()); + } + + // Try to load the module we found. + switch (ModuleManager->ReadAST(ModuleFile->getName(), + serialization::MK_Module)) { + case ASTReader::Success: + break; + + case ASTReader::IgnorePCH: + // FIXME: The ASTReader will already have complained, but can we showhorn + // that diagnostic information into a more useful form? + return 0; + + case ASTReader::Failure: + // Already complained. + return 0; + } + + // FIXME: The module file's FileEntry makes a poor key indeed! + return (ModuleKey)ModuleFile; +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index 0371dae..432407a 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -60,6 +60,16 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { } } +static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) { + switch (Kind) { + default: + llvm_unreachable("Unknown analysis client!"); +#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \ + case NAME: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + //===----------------------------------------------------------------------===// // Serialization (to args) //===----------------------------------------------------------------------===// @@ -68,7 +78,7 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, std::vector<std::string> &Res) { if (Opts.ShowCheckerHelp) Res.push_back("-analyzer-checker-help"); - if (Opts.AnalysisStoreOpt != BasicStoreModel) { + if (Opts.AnalysisStoreOpt != RegionStoreModel) { Res.push_back("-analyzer-store"); Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt)); } @@ -80,6 +90,10 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-output"); Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt)); } + if (Opts.AnalysisPurgeOpt != PurgeStmt) { + Res.push_back("-analyzer-purge"); + Res.push_back(getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt)); + } if (!Opts.AnalyzeSpecificFunction.empty()) { Res.push_back("-analyze-function"); Res.push_back(Opts.AnalyzeSpecificFunction); @@ -92,8 +106,6 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-opt-analyze-nested-blocks"); if (Opts.EagerlyAssume) Res.push_back("-analyzer-eagerly-assume"); - if (!Opts.PurgeDead) - Res.push_back("-analyzer-no-purge-dead"); if (Opts.TrimGraph) Res.push_back("-trim-egraph"); if (Opts.VisualizeEGDot) @@ -171,6 +183,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-mcode-model"); Res.push_back(Opts.CodeModel); } + if (Opts.CUDAIsDevice) + Res.push_back("-fcuda-is-device"); if (!Opts.CXAAtExit) Res.push_back("-fno-use-cxa-atexit"); if (Opts.CXXCtorDtorAliases) @@ -207,6 +221,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-mregparm"); Res.push_back(llvm::utostr(Opts.NumRegisterParameters)); } + if (Opts.NoGlobalMerge) + Res.push_back("-mno-global-merge"); if (Opts.NoExecStack) Res.push_back("-mnoexecstack"); if (Opts.RelaxAll) @@ -361,7 +377,6 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::ASTDumpXML: return "-ast-dump-xml"; case frontend::ASTPrint: return "-ast-print"; case frontend::ASTView: return "-ast-view"; - case frontend::CreateModule: return "-create-module"; case frontend::DumpRawTokens: return "-dump-raw-tokens"; case frontend::DumpTokens: return "-dump-tokens"; case frontend::EmitAssembly: return "-S"; @@ -372,6 +387,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::EmitCodeGenOnly: return "-emit-codegen-only"; case frontend::EmitObj: return "-emit-obj"; case frontend::FixIt: return "-fixit"; + case frontend::GenerateModule: return "-emit-module"; case frontend::GeneratePCH: return "-emit-pch"; case frontend::GeneratePTH: return "-emit-pth"; case frontend::InitOnly: return "-init-only"; @@ -404,8 +420,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-disable-free"); if (Opts.RelocatablePCH) Res.push_back("-relocatable-pch"); - if (Opts.ChainedPCH) - Res.push_back("-chained-pch"); if (Opts.ShowHelp) Res.push_back("-help"); if (Opts.ShowMacrosInCodeCompletion) @@ -439,6 +453,12 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-arcmt-migrate-directory"); Res.push_back(Opts.ARCMTMigrateDir); } + if (!Opts.ARCMTMigrateReportOut.empty()) { + Res.push_back("-arcmt-migrate-report-output"); + Res.push_back(Opts.ARCMTMigrateReportOut); + } + if (Opts.ARCMTMigrateEmitARCErrors) + Res.push_back("-arcmt-migrate-emit-errors"); bool NeedLang = false; for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) @@ -491,10 +511,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-ast-merge"); Res.push_back(Opts.ASTMergeFiles[i]); } - for (unsigned i = 0, e = Opts.Modules.size(); i != e; ++i) { - Res.push_back("-import-module"); - Res.push_back(Opts.Modules[i]); - } for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) { Res.push_back("-mllvm"); Res.push_back(Opts.LLVMArgs[i]); @@ -514,17 +530,43 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied)) llvm::report_fatal_error("Invalid option set!"); if (E.IsUserSupplied) { - if (E.Group == frontend::After) { + switch (E.Group) { + case frontend::After: Res.push_back("-idirafter"); - } else if (E.Group == frontend::Quoted) { + break; + + case frontend::Quoted: Res.push_back("-iquote"); - } else if (E.Group == frontend::System) { + break; + + case frontend::System: Res.push_back("-isystem"); - } else if (E.Group == frontend::CXXSystem) { + break; + + case frontend::IndexHeaderMap: + Res.push_back("-index-header-map"); + Res.push_back(E.IsFramework? "-F" : "-I"); + break; + + case frontend::CSystem: + Res.push_back("-c-isystem"); + break; + + case frontend::CXXSystem: Res.push_back("-cxx-isystem"); - } else { - assert(E.Group == frontend::Angled && "Invalid group!"); + break; + + case frontend::ObjCSystem: + Res.push_back("-objc-isystem"); + break; + + case frontend::ObjCXXSystem: + Res.push_back("-objcxx-isystem"); + break; + + case frontend::Angled: Res.push_back(E.IsFramework ? "-F" : "-I"); + break; } } else { if (E.Group != frontend::Angled && E.Group != frontend::System) @@ -535,32 +577,16 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, Res.push_back(E.Path); } - if (!Opts.EnvIncPath.empty()) { - // FIXME: Provide an option for this, and move env detection to driver. - llvm::report_fatal_error("Not yet implemented!"); - } - if (!Opts.CEnvIncPath.empty()) { - // FIXME: Provide an option for this, and move env detection to driver. - llvm::report_fatal_error("Not yet implemented!"); - } - if (!Opts.ObjCEnvIncPath.empty()) { - // FIXME: Provide an option for this, and move env detection to driver. - llvm::report_fatal_error("Not yet implemented!"); - } - if (!Opts.CXXEnvIncPath.empty()) { - // FIXME: Provide an option for this, and move env detection to driver. - llvm::report_fatal_error("Not yet implemented!"); - } - if (!Opts.ObjCXXEnvIncPath.empty()) { - // FIXME: Provide an option for this, and move env detection to driver. - llvm::report_fatal_error("Not yet implemented!"); - } if (!Opts.ResourceDir.empty()) { Res.push_back("-resource-dir"); Res.push_back(Opts.ResourceDir); } - if (!Opts.UseStandardIncludes) - Res.push_back("-nostdinc"); + if (!Opts.ModuleCachePath.empty()) { + Res.push_back("-fmodule-cache-path"); + Res.push_back(Opts.ModuleCachePath); + } + if (!Opts.UseStandardSystemIncludes) + Res.push_back("-nostdsysteminc"); if (!Opts.UseStandardCXXIncludes) Res.push_back("-nostdinc++"); if (Opts.UseLibcxx) @@ -593,16 +619,14 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fno-gnu-keywords"); if (!Opts.GNUMode && Opts.GNUKeywords) Res.push_back("-fgnu-keywords"); - if (Opts.Microsoft) + if (Opts.MicrosoftExt) Res.push_back("-fms-extensions"); if (Opts.MSCVersion != 0) Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion)); if (Opts.Borland) Res.push_back("-fborland-extensions"); - if (Opts.ObjCNonFragileABI) - Res.push_back("-fobjc-nonfragile-abi"); - if (Opts.ObjCNonFragileABI2) - Res.push_back("-fobjc-nonfragile-abi"); + if (!Opts.ObjCNonFragileABI) + Res.push_back("-fobjc-fragile-abi"); if (Opts.ObjCDefaultSynthProperties) Res.push_back("-fobjc-default-synthesize-properties"); // NoInline is implicit. @@ -650,6 +674,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-pthread"); if (Opts.Blocks) Res.push_back("-fblocks"); + if (Opts.BlocksRuntimeOptional) + Res.push_back("-fblocks-runtime-optional"); if (Opts.EmitAllDecls) Res.push_back("-femit-all-decls"); if (Opts.MathErrno) @@ -692,11 +718,11 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fshort-wchar"); if (!Opts.ElideConstructors) Res.push_back("-fno-elide-constructors"); - if (Opts.getGCMode() != LangOptions::NonGC) { - if (Opts.getGCMode() == LangOptions::HybridGC) { + if (Opts.getGC() != LangOptions::NonGC) { + if (Opts.getGC() == LangOptions::HybridGC) { Res.push_back("-fobjc-gc"); } else { - assert(Opts.getGCMode() == LangOptions::GCOnly && "Invalid GC mode!"); + assert(Opts.getGC() == LangOptions::GCOnly && "Invalid GC mode!"); Res.push_back("-fobjc-gc-only"); } } @@ -723,9 +749,9 @@ static void LangOptsToArgs(const LangOptions &Opts, if (Opts.InlineVisibilityHidden) Res.push_back("-fvisibility-inlines-hidden"); - if (Opts.getStackProtectorMode() != 0) { + if (Opts.getStackProtector() != 0) { Res.push_back("-stack-protector"); - Res.push_back(llvm::utostr(Opts.getStackProtectorMode())); + Res.push_back(llvm::utostr(Opts.getStackProtector())); } if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) { Res.push_back("-ftemplate-depth"); @@ -860,7 +886,7 @@ using namespace clang::driver::cc1options; // static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { unsigned DefaultOpt = 0; if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable)) DefaultOpt = 2; @@ -870,11 +896,11 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, } static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { using namespace cc1options; if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { - llvm::StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(Args); AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name) #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, NAME##Model) @@ -889,7 +915,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) { - llvm::StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(Args); AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name) #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, NAME##Model) @@ -904,7 +930,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_output)) { - llvm::StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(Args); AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name) #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \ .Case(CMDFLAG, PD_##NAME) @@ -918,6 +944,21 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.AnalysisDiagOpt = Value; } + if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) { + StringRef Name = A->getValue(Args); + AnalysisPurgeMode Value = llvm::StringSwitch<AnalysisPurgeMode>(Name) +#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \ + .Case(CMDFLAG, NAME) +#include "clang/Frontend/Analyses.def" + .Default(NumPurgeModes); + // FIXME: Error handling. + if (Value == NumPurgeModes) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << Name; + else + Opts.AnalysisPurgeOpt = Value; + } + Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help); Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz); Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); @@ -925,7 +966,6 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); Opts.AnalyzeNestedBlocks = Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); - Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function); Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG); @@ -946,8 +986,8 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, bool enable = (A->getOption().getID() == OPT_analyzer_checker); // We can have a list of comma separated checker names, e.g: // '-analyzer-checker=cocoa,unix' - llvm::StringRef checkerList = A->getValue(Args); - llvm::SmallVector<llvm::StringRef, 4> checkers; + StringRef checkerList = A->getValue(Args); + SmallVector<StringRef, 4> checkers; checkerList.split(checkers, ","); for (unsigned i = 0, e = checkers.size(); i != e; ++i) Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable)); @@ -955,7 +995,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { using namespace cc1options; Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags); @@ -992,6 +1032,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.ObjCRuntimeHasARC = Args.hasArg(OPT_fobjc_runtime_has_arc); Opts.ObjCRuntimeHasTerminate = Args.hasArg(OPT_fobjc_runtime_has_terminate); + Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model); @@ -1006,6 +1047,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option); 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.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer); @@ -1030,7 +1072,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file); if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { - llvm::StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(Args); unsigned Method = llvm::StringSwitch<unsigned>(Name) .Case("legacy", CodeGenOptions::Legacy) .Case("non-legacy", CodeGenOptions::NonLegacy) @@ -1056,7 +1098,7 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, } static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { using namespace cc1options; Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file); Opts.IgnoreWarnings = Args.hasArg(OPT_w); @@ -1080,18 +1122,18 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, if (A->getOption().matches(OPT_fdiagnostics_show_note_include_stack)) Opts.ShowNoteIncludeStack = true; - llvm::StringRef ShowOverloads = + StringRef ShowOverloads = Args.getLastArgValue(OPT_fshow_overloads_EQ, "all"); if (ShowOverloads == "best") - Opts.ShowOverloads = Diagnostic::Ovl_Best; + Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best; else if (ShowOverloads == "all") - Opts.ShowOverloads = Diagnostic::Ovl_All; + Opts.ShowOverloads = DiagnosticsEngine::Ovl_All; else Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args) << ShowOverloads; - llvm::StringRef ShowCategory = + StringRef ShowCategory = Args.getLastArgValue(OPT_fdiagnostics_show_category, "none"); if (ShowCategory == "none") Opts.ShowCategories = 0; @@ -1104,7 +1146,7 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) << ShowCategory; - llvm::StringRef Format = + StringRef Format = Args.getLastArgValue(OPT_fdiagnostics_format, "clang"); if (Format == "clang") Opts.Format = DiagnosticOptions::Clang; @@ -1145,13 +1187,13 @@ static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) { } static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { using namespace cc1options; Opts.ProgramAction = frontend::ParseSyntaxOnly; if (const Arg *A = Args.getLastArg(OPT_Action_Group)) { switch (A->getOption().getID()) { default: - assert(0 && "Invalid option in group!"); + llvm_unreachable("Invalid option in group!"); case OPT_ast_dump: Opts.ProgramAction = frontend::ASTDump; break; case OPT_ast_dump_xml: @@ -1183,6 +1225,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, // fall-through! case OPT_fixit: Opts.ProgramAction = frontend::FixIt; break; + case OPT_emit_module: + Opts.ProgramAction = frontend::GenerateModule; break; case OPT_emit_pch: Opts.ProgramAction = frontend::GeneratePCH; break; case OPT_emit_pth: @@ -1207,8 +1251,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::RunAnalysis; break; case OPT_Eonly: Opts.ProgramAction = frontend::RunPreprocessorOnly; break; - case OPT_create_module: - Opts.ProgramAction = frontend::CreateModule; break; } } @@ -1246,7 +1288,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.OutputFile = Args.getLastArgValue(OPT_o); Opts.Plugins = Args.getAllArgValues(OPT_load); Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); - Opts.ChainedPCH = Args.hasArg(OPT_chained_pch); Opts.ShowHelp = Args.hasArg(OPT_help); Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); Opts.ShowCodePatternsInCodeCompletion @@ -1259,7 +1300,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge); Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can); - Opts.Modules = Args.getAllArgValues(OPT_import_module); Opts.ARCMTAction = FrontendOptions::ARCMT_None; if (const Arg *A = Args.getLastArg(OPT_arcmt_check, @@ -1280,6 +1320,10 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, } } Opts.ARCMTMigrateDir = Args.getLastArgValue(OPT_arcmt_migrate_directory); + Opts.ARCMTMigrateReportOut + = Args.getLastArgValue(OPT_arcmt_migrate_report_output); + Opts.ARCMTMigrateEmitARCErrors + = Args.hasArg(OPT_arcmt_migrate_emit_arc_errors); InputKind DashX = IK_None; if (const Arg *A = Args.getLastArg(OPT_x)) { @@ -1296,7 +1340,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("objective-c-cpp-output", IK_PreprocessedObjC) .Case("objc-cpp-output", IK_PreprocessedObjC) .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX) + .Case("objc++-cpp-output", IK_PreprocessedObjCXX) .Case("c-header", IK_C) + .Case("cl-header", IK_OpenCL) .Case("objective-c-header", IK_ObjC) .Case("c++-header", IK_CXX) .Case("objective-c++-header", IK_ObjCXX) @@ -1317,7 +1363,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, InputKind IK = DashX; if (IK == IK_None) { IK = FrontendOptions::getInputKindForExtension( - llvm::StringRef(Inputs[i]).rsplit('.').second); + StringRef(Inputs[i]).rsplit('.').second); // FIXME: Remove this hack. if (i == 0) DashX = IK; @@ -1350,20 +1396,35 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); - Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc); + Opts.UseStandardSystemIncludes = !Args.hasArg(OPT_nostdsysteminc); Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx); if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ)) Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0); Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); - - // Add -I... and -F... options in order. - for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F), - ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::Angled, true, + Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path); + Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); + + // Add -I..., -F..., and -index-header-map options in order. + bool IsIndexHeaderMap = false; + for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F, + OPT_index_header_map), + ie = Args.filtered_end(); it != ie; ++it) { + if ((*it)->getOption().matches(OPT_index_header_map)) { + // -index-header-map applies to the next -I or -F. + IsIndexHeaderMap = true; + continue; + } + + frontend::IncludeDirGroup Group + = IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled; + + Opts.AddPath((*it)->getValue(Args), Group, true, /*IsFramework=*/ (*it)->getOption().matches(OPT_F), false); + IsIndexHeaderMap = false; + } // Add -iprefix/-iwith-prefix/-iwithprefixbefore options. - llvm::StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. + StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix, OPT_iwithprefixbefore), ie = Args.filtered_end(); it != ie; ++it) { @@ -1384,14 +1445,25 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { for (arg_iterator it = Args.filtered_begin(OPT_iquote), ie = Args.filtered_end(); it != ie; ++it) Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, false); - for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem, OPT_isystem, + for (arg_iterator it = Args.filtered_begin(OPT_isystem, OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), - ((*it)->getOption().matches(OPT_cxx_isystem) ? - frontend::CXXSystem : frontend::System), - true, false, !(*it)->getOption().matches(OPT_iwithsysroot)); - - // FIXME: Need options for the various environment variables! + Opts.AddPath((*it)->getValue(Args), frontend::System, true, false, + !(*it)->getOption().matches(OPT_iwithsysroot)); + + // Add the paths for the various language specific isystem flags. + for (arg_iterator it = Args.filtered_begin(OPT_c_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath((*it)->getValue(Args), frontend::CSystem, true, false, true); + for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath((*it)->getValue(Args), frontend::CXXSystem, true, false, true); + for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath((*it)->getValue(Args), frontend::ObjCSystem, true, false,true); + for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath((*it)->getValue(Args), frontend::ObjCXXSystem, true, false, + true); } void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, @@ -1414,7 +1486,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, case IK_None: case IK_AST: case IK_LLVM_IR: - assert(0 && "Invalid input kind!"); + llvm_unreachable("Invalid input kind!"); case IK_OpenCL: LangStd = LangStandard::lang_opencl; break; @@ -1452,9 +1524,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, // OpenCL has some additional defaults. if (LangStd == LangStandard::lang_opencl) { Opts.OpenCL = 1; - Opts.AltiVec = 1; + Opts.AltiVec = 0; Opts.CXXOperatorNames = 1; - Opts.LaxVectorConversions = 1; + Opts.LaxVectorConversions = 0; Opts.DefaultFPContract = 1; } @@ -1475,7 +1547,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, } static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { // FIXME: Cleanup per-file based stuff. LangStandard::Kind LangStd = LangStandard::lang_unspecified; if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { @@ -1545,12 +1617,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Opts.ObjC1) { if (Args.hasArg(OPT_fobjc_gc_only)) - Opts.setGCMode(LangOptions::GCOnly); + Opts.setGC(LangOptions::GCOnly); else if (Args.hasArg(OPT_fobjc_gc)) - Opts.setGCMode(LangOptions::HybridGC); + Opts.setGC(LangOptions::HybridGC); else if (Args.hasArg(OPT_fobjc_arc)) { Opts.ObjCAutoRefCount = 1; - if (!Args.hasArg(OPT_fobjc_nonfragile_abi)) + if (Args.hasArg(OPT_fobjc_fragile_abi)) Diags.Report(diag::err_arc_nonfragile_abi); } @@ -1585,7 +1657,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fdelayed_template_parsing)) Opts.DelayedTemplateParsing = 1; - llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); + StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); if (Vis == "default") Opts.setVisibilityMode(DefaultVisibility); else if (Vis == "hidden") @@ -1615,7 +1687,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, OPT_fno_dollars_in_identifiers, Opts.DollarIdents); Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); - Opts.Microsoft = Args.hasArg(OPT_fms_extensions); + Opts.MicrosoftExt = Args.hasArg(OPT_fms_extensions); + Opts.MicrosoftMode = Args.hasArg(OPT_fms_compatibility); Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags); Opts.Borland = Args.hasArg(OPT_fborland_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); @@ -1633,6 +1706,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.RTTI = !Args.hasArg(OPT_fno_rtti); Opts.Blocks = Args.hasArg(OPT_fblocks); + Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); Opts.ShortEnums = Args.hasArg(OPT_fshort_enums); @@ -1653,13 +1727,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); Opts.ObjCConstantStringClass = Args.getLastArgValue(OPT_fconstant_string_class); - Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); + Opts.ObjCNonFragileABI = !Args.hasArg(OPT_fobjc_fragile_abi); if (Opts.ObjCNonFragileABI) Opts.ObjCNonFragileABI2 = true; Opts.ObjCDefaultSynthProperties = Args.hasArg(OPT_fobjc_default_synthesize_properties); Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); + Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct, 0, Diags); Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags); Opts.Static = Args.hasArg(OPT_static_define); Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts); @@ -1696,15 +1771,15 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP; break; - case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break; - case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break; - case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break; + case 0: Opts.setStackProtector(LangOptions::SSPOff); break; + case 1: Opts.setStackProtector(LangOptions::SSPOn); break; + case 2: Opts.setStackProtector(LangOptions::SSPReq); break; } } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, FileManager &FileMgr, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { using namespace cc1options; Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); @@ -1714,6 +1789,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.TokenCache = Opts.ImplicitPTHInclude; Opts.UsePredefines = !Args.hasArg(OPT_undef); Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); + Opts.AutoModuleImport = Args.hasArg(OPT_fauto_module_import); Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch); Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls); @@ -1724,12 +1800,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, } if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { - llvm::StringRef Value(A->getValue(Args)); + StringRef Value(A->getValue(Args)); size_t Comma = Value.find(','); unsigned Bytes = 0; unsigned EndOfLine = 0; - if (Comma == llvm::StringRef::npos || + if (Comma == StringRef::npos || Value.substr(0, Comma).getAsInteger(10, Bytes) || Value.substr(Comma + 1).getAsInteger(10, EndOfLine)) Diags.Report(diag::err_drv_preamble_format); @@ -1780,8 +1856,8 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, for (arg_iterator it = Args.filtered_begin(OPT_remap_file), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; - std::pair<llvm::StringRef,llvm::StringRef> Split = - llvm::StringRef(A->getValue(Args)).split(';'); + std::pair<StringRef,StringRef> Split = + StringRef(A->getValue(Args)).split(';'); if (Split.second.empty()) { Diags.Report(diag::err_drv_invalid_remap_file) << A->getAsString(Args); @@ -1792,7 +1868,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) { - llvm::StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(Args); unsigned Library = llvm::StringSwitch<unsigned>(Name) .Case("libc++", ARCXX_libcxx) .Case("libstdc++", ARCXX_libstdcxx) @@ -1834,7 +1910,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, const char *const *ArgBegin, const char *const *ArgEnd, - Diagnostic &Diags) { + DiagnosticsEngine &Diags) { // Parse the arguments. llvm::OwningPtr<OptTable> Opts(createCC1OptTable()); unsigned MissingArgIndex, MissingArgCount; @@ -1873,3 +1949,105 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); ParseTargetArgs(Res.getTargetOpts(), *Args); } + +namespace { + + class ModuleSignature { + llvm::SmallVector<uint64_t, 16> Data; + unsigned CurBit; + uint64_t CurValue; + + public: + ModuleSignature() : CurBit(0), CurValue(0) { } + + void add(uint64_t Value, unsigned Bits); + void add(StringRef Value); + void flush(); + + llvm::APInt getAsInteger() const; + }; +} + +void ModuleSignature::add(uint64_t Value, unsigned int NumBits) { + CurValue |= Value << CurBit; + if (CurBit + NumBits < 64) { + CurBit += NumBits; + return; + } + + // Add the current word. + Data.push_back(CurValue); + + if (CurBit) + CurValue = Value >> (64-CurBit); + else + CurValue = 0; + CurBit = (CurBit+NumBits) & 63; +} + +void ModuleSignature::flush() { + if (CurBit == 0) + return; + + Data.push_back(CurValue); + CurBit = 0; + CurValue = 0; +} + +void ModuleSignature::add(StringRef Value) { + for (StringRef::iterator I = Value.begin(), IEnd = Value.end(); I != IEnd;++I) + add(*I, 8); +} + +llvm::APInt ModuleSignature::getAsInteger() const { + return llvm::APInt(Data.size() * 64, Data); +} + +std::string CompilerInvocation::getModuleHash() const { + ModuleSignature Signature; + + // Start the signature with the compiler version. + Signature.add(getClangFullRepositoryVersion()); + + // Extend the signature with the language options +#define LANGOPT(Name, Bits, Default, Description) \ + Signature.add(LangOpts.Name, Bits); +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + Signature.add(static_cast<unsigned>(LangOpts.get##Name()), Bits); +#define BENIGN_LANGOPT(Name, Bits, Default, Description) +#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#include "clang/Basic/LangOptions.def" + + // Extend the signature with the target triple + llvm::Triple T(TargetOpts.Triple); + Signature.add((unsigned)T.getArch(), 5); + Signature.add((unsigned)T.getVendor(), 4); + Signature.add((unsigned)T.getOS(), 5); + Signature.add((unsigned)T.getEnvironment(), 4); + + // Extend the signature with preprocessor options. + Signature.add(getPreprocessorOpts().UsePredefines, 1); + Signature.add(getPreprocessorOpts().DetailedRecord, 1); + + // Hash the preprocessor defines. + // FIXME: This is terrible. Use an MD5 sum of the preprocessor defines. + std::vector<StringRef> MacroDefs; + for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator + I = getPreprocessorOpts().Macros.begin(), + IEnd = getPreprocessorOpts().Macros.end(); + I != IEnd; ++I) { + if (!I->second) + MacroDefs.push_back(I->first); + } + llvm::array_pod_sort(MacroDefs.begin(), MacroDefs.end()); + + unsigned PPHashResult = 0; + for (unsigned I = 0, N = MacroDefs.size(); I != N; ++I) + PPHashResult = llvm::HashString(MacroDefs[I], PPHashResult); + Signature.add(PPHashResult, 32); + + // We've generated the signature. Treat it as one large APInt that we'll + // encode in base-36 and return. + Signature.flush(); + return Signature.getAsInteger().toString(36, /*Signed=*/false); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp index 42b648a..fc15081 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -29,8 +29,8 @@ using namespace clang; /// \return A CompilerInvocation, or 0 if none was built for the given /// argument vector. CompilerInvocation * -clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList, - llvm::IntrusiveRefCntPtr<Diagnostic> Diags) { +clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList, + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -39,7 +39,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList, ArgList.begin()); } - llvm::SmallVector<const char *, 16> Args; + SmallVector<const char *, 16> Args; Args.push_back("<clang>"); // FIXME: Remove dummy argument. Args.insert(Args.end(), ArgList.begin(), ArgList.end()); @@ -49,7 +49,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList, // FIXME: We shouldn't have to pass in the path info. driver::Driver TheDriver("clang", llvm::sys::getHostTriple(), - "a.out", false, false, *Diags); + "a.out", false, *Diags); // Don't check that inputs exist, they may have been remapped. TheDriver.setCheckInputsExist(false); @@ -74,7 +74,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList, } const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin()); - if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { + if (StringRef(Cmd->getCreator().getName()) != "clang") { Diags->Report(diag::err_fe_expected_clang_command); return 0; } diff --git a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp index 1edd09b..ff3a123 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp @@ -32,19 +32,19 @@ class DependencyFileCallback : public PPCallbacks { llvm::StringSet<> FilesSet; const Preprocessor *PP; std::vector<std::string> Targets; - llvm::raw_ostream *OS; + raw_ostream *OS; bool IncludeSystemHeaders; bool PhonyTarget; bool AddMissingHeaderDeps; private: bool FileMatchesDepCriteria(const char *Filename, SrcMgr::CharacteristicKind FileType); - void AddFilename(llvm::StringRef Filename); + void AddFilename(StringRef Filename); void OutputDependencyFile(); public: DependencyFileCallback(const Preprocessor *_PP, - llvm::raw_ostream *_OS, + raw_ostream *_OS, const DependencyOutputOptions &Opts) : PP(_PP), Targets(Opts.Targets), OS(_OS), IncludeSystemHeaders(Opts.IncludeSystemHeaders), @@ -52,15 +52,16 @@ public: AddMissingHeaderDeps(Opts.AddMissingHeaderDeps) {} virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType); + SrcMgr::CharacteristicKind FileType, + FileID PrevFID); virtual void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, - llvm::StringRef FileName, + StringRef FileName, bool IsAngled, const FileEntry *File, SourceLocation EndLoc, - llvm::StringRef SearchPath, - llvm::StringRef RelativePath); + StringRef SearchPath, + StringRef RelativePath); virtual void EndOfMainFile() { OutputDependencyFile(); @@ -78,7 +79,7 @@ void clang::AttachDependencyFileGen(Preprocessor &PP, } std::string Err; - llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err)); + raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err)); if (!Err.empty()) { PP.getDiagnostics().Report(diag::err_fe_error_opening) << Opts.OutputFile << Err; @@ -86,14 +87,8 @@ void clang::AttachDependencyFileGen(Preprocessor &PP, } // Disable the "file not found" diagnostic if the -MG option was given. - // FIXME: Ideally this would live in the driver, but we don't have the ability - // to remap individual diagnostics there without creating a DiagGroup, in - // which case we would need to prevent the group name from showing up in - // diagnostics. - if (Opts.AddMissingHeaderDeps) { - PP.getDiagnostics().setDiagnosticMapping(diag::warn_pp_file_not_found, - diag::MAP_IGNORE, SourceLocation()); - } + if (Opts.AddMissingHeaderDeps) + PP.SetSuppressIncludeNotFoundError(true); PP.addPPCallbacks(new DependencyFileCallback(&PP, OS, Opts)); } @@ -113,7 +108,8 @@ bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename, void DependencyFileCallback::FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType) { + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) { if (Reason != PPCallbacks::EnterFile) return; @@ -123,10 +119,10 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc, SourceManager &SM = PP->getSourceManager(); const FileEntry *FE = - SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc))); + SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc))); if (FE == 0) return; - llvm::StringRef Filename = FE->getName(); + StringRef Filename = FE->getName(); if (!FileMatchesDepCriteria(Filename.data(), FileType)) return; @@ -143,24 +139,24 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc, void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, - llvm::StringRef FileName, + StringRef FileName, bool IsAngled, const FileEntry *File, SourceLocation EndLoc, - llvm::StringRef SearchPath, - llvm::StringRef RelativePath) { + StringRef SearchPath, + StringRef RelativePath) { if (AddMissingHeaderDeps && !File) AddFilename(FileName); } -void DependencyFileCallback::AddFilename(llvm::StringRef Filename) { +void DependencyFileCallback::AddFilename(StringRef Filename) { if (FilesSet.insert(Filename)) Files.push_back(Filename); } /// PrintFilename - GCC escapes spaces, but apparently not ' or " or other /// scary characters. -static void PrintFilename(llvm::raw_ostream &OS, llvm::StringRef Filename) { +static void PrintFilename(raw_ostream &OS, StringRef Filename) { for (unsigned i = 0, e = Filename.size(); i != e; ++i) { if (Filename[i] == ' ') OS << '\\'; diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp index 0128d6e..ba2d63b 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp @@ -20,6 +20,7 @@ #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Parse/ParseAST.h" #include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ChainedIncludesSource.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Timer.h" @@ -65,7 +66,7 @@ public: if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) { unsigned DiagID - = Ctx.getDiagnostics().getCustomDiagID(Diagnostic::Error, + = Ctx.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0 was deserialized"); Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID) << ND->getNameAsString(); @@ -82,7 +83,7 @@ FrontendAction::FrontendAction() : Instance(0) {} FrontendAction::~FrontendAction() {} -void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind, +void FrontendAction::setCurrentFile(StringRef Value, InputKind Kind, ASTUnit *AST) { CurrentFile = Value; CurrentFileKind = Kind; @@ -90,7 +91,7 @@ void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind, } ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { ASTConsumer* Consumer = CreateASTConsumer(CI, InFile); if (!Consumer) return 0; @@ -123,7 +124,7 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, } bool FrontendAction::BeginSourceFile(CompilerInstance &CI, - llvm::StringRef Filename, + StringRef Filename, InputKind InputKind) { assert(!Instance && "Already processing a source file!"); assert(!Filename.empty() && "Unexpected empty filename!"); @@ -141,7 +142,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, assert(hasASTFileSupport() && "This action does not have AST file support!"); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics()); + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); std::string Error; ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags, CI.getFileSystemOpts()); @@ -224,9 +225,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { // Use PCH. assert(hasPCHSupport() && "This action does not have PCH support!"); - ASTDeserializationListener *DeserialListener - = CI.getInvocation().getFrontendOpts().ChainedPCH ? - Consumer->GetASTDeserializationListener() : 0; + ASTDeserializationListener *DeserialListener = + Consumer->GetASTDeserializationListener(); if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls) DeserialListener = new DeserializedDeclsDumper(DeserialListener); if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty()) @@ -247,7 +247,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, goto failure; } - // Initialize builtin info as long as we aren't using an external AST + // Initialize built-in info as long as we aren't using an external AST // source. if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { Preprocessor &PP = CI.getPreprocessor(); @@ -374,26 +374,26 @@ void ASTFrontendAction::ExecuteAction() { CompletionConsumer = &CI.getCodeCompletionConsumer(); if (!CI.hasSema()) - CI.createSema(usesCompleteTranslationUnit(), CompletionConsumer); + CI.createSema(getTranslationUnitKind(), CompletionConsumer); ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats); } ASTConsumer * PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); } ASTConsumer *WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return WrappedAction->CreateASTConsumer(CI, InFile); } bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) { return WrappedAction->BeginInvocation(CI); } bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI, - llvm::StringRef Filename) { + StringRef Filename) { WrappedAction->setCurrentFile(getCurrentFile(), getCurrentFileKind()); WrappedAction->setCompilerInstance(&CI); return WrappedAction->BeginSourceFileAction(CI, Filename); @@ -408,8 +408,8 @@ void WrapperFrontendAction::EndSourceFileAction() { bool WrapperFrontendAction::usesPreprocessorOnly() const { return WrappedAction->usesPreprocessorOnly(); } -bool WrapperFrontendAction::usesCompleteTranslationUnit() { - return WrappedAction->usesCompleteTranslationUnit(); +TranslationUnitKind WrapperFrontendAction::getTranslationUnitKind() { + return WrappedAction->getTranslationUnitKind(); } bool WrapperFrontendAction::hasPCHSupport() const { return WrappedAction->hasPCHSupport(); diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp index 7b06c7e..6f84da9 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp @@ -22,6 +22,8 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + using namespace clang; //===----------------------------------------------------------------------===// @@ -29,7 +31,7 @@ using namespace clang; //===----------------------------------------------------------------------===// ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return new ASTConsumer(); } @@ -41,20 +43,20 @@ void InitOnlyAction::ExecuteAction() { //===----------------------------------------------------------------------===// ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + StringRef InFile) { + if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) return CreateASTPrinter(OS); return 0; } ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return CreateASTDumper(); } ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - llvm::raw_ostream *OS; + StringRef InFile) { + raw_ostream *OS; if (CI.getFrontendOpts().OutputFile.empty()) OS = &llvm::outs(); else @@ -64,35 +66,34 @@ ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI, } ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return CreateASTViewer(); } ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return CreateDeclContextPrinter(); } ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { std::string Sysroot; std::string OutputFile; - llvm::raw_ostream *OS = 0; - bool Chaining; - if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS, Chaining)) + raw_ostream *OS = 0; + if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS)) return 0; - const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? - Sysroot.c_str() : 0; - return new PCHGenerator(CI.getPreprocessor(), OutputFile, Chaining, isysroot, OS); + if (!CI.getFrontendOpts().RelocatablePCH) + Sysroot.clear(); + return new PCHGenerator(CI.getPreprocessor(), OutputFile, MakeModule, + Sysroot, OS); } bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, - llvm::StringRef InFile, + StringRef InFile, std::string &Sysroot, std::string &OutputFile, - llvm::raw_ostream *&OS, - bool &Chaining) { + raw_ostream *&OS) { Sysroot = CI.getHeaderSearchOpts().Sysroot; if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) { CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot); @@ -101,19 +102,19 @@ bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, // We use createOutputFile here because this is exposed via libclang, and we // must disable the RemoveFileOnSignal behavior. + // We use a temporary to avoid race conditions. OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true, - /*RemoveFileOnSignal=*/false, InFile); + /*RemoveFileOnSignal=*/false, InFile, + /*Extension=*/"", /*useTemporary=*/true); if (!OS) return true; OutputFile = CI.getFrontendOpts().OutputFile; - Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH && - !CI.getPreprocessorOpts().ImplicitPCHInclude.empty(); return false; } ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { + StringRef InFile) { return new ASTConsumer(); } @@ -182,9 +183,48 @@ void PreprocessOnlyAction::ExecuteAction() { void PrintPreprocessedAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); - // Output file needs to be set to 'Binary', to avoid converting Unix style + // Output file may need to be set to 'Binary', to avoid converting Unix style // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>). - llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + // + // Look to see what type of line endings the file uses. If there's a + // CRLF, then we won't open the file up in binary mode. If there is + // just an LF or CR, then we will open the file up in binary mode. + // In this fashion, the output format should match the input format, unless + // the input format has inconsistent line endings. + // + // This should be a relatively fast operation since most files won't have + // all of their source code on a single line. However, that is still a + // concern, so if we scan for too long, we'll just assume the file should + // be opened in binary mode. + bool BinaryMode = true; + bool InvalidFile = false; + const SourceManager& SM = CI.getSourceManager(); + const llvm::MemoryBuffer *Buffer = SM.getBuffer(SM.getMainFileID(), + &InvalidFile); + if (!InvalidFile) { + const char *cur = Buffer->getBufferStart(); + const char *end = Buffer->getBufferEnd(); + const char *next = (cur != end) ? cur + 1 : end; + + // Limit ourselves to only scanning 256 characters into the source + // file. This is mostly a sanity check in case the file has no + // newlines whatsoever. + if (end - cur > 256) end = cur + 256; + + while (next < end) { + if (*cur == 0x0D) { // CR + if (*next == 0x0A) // CRLF + BinaryMode = false; + + break; + } else if (*cur == 0x0A) // LF + break; + + ++cur, ++next; + } + } + + raw_ostream *OS = CI.createDefaultOutputFile(BinaryMode, getCurrentFile()); if (!OS) return; DoPrintPreprocessedInput(CI.getPreprocessor(), OS, @@ -217,7 +257,7 @@ void PrintPreambleAction::ExecuteAction() { llvm::MemoryBuffer *Buffer = CI.getFileManager().getBufferForFile(getCurrentFile()); if (Buffer) { - unsigned Preamble = Lexer::ComputePreamble(Buffer).first; + unsigned Preamble = Lexer::ComputePreamble(Buffer, CI.getLangOpts()).first; llvm::outs().write(Buffer->getBufferStart(), Preamble); delete Buffer; } diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp index 0a20051..ea4005f 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp @@ -11,7 +11,7 @@ #include "llvm/ADT/StringSwitch.h" using namespace clang; -InputKind FrontendOptions::getInputKindForExtension(llvm::StringRef Extension) { +InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) { return llvm::StringSwitch<InputKind>(Extension) .Case("ast", IK_AST) .Case("c", IK_C) diff --git a/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp b/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp index 51dec96..3b41d89 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp @@ -17,7 +17,7 @@ using namespace clang; namespace { class HeaderIncludesCallback : public PPCallbacks { SourceManager &SM; - llvm::raw_ostream *OutputFile; + raw_ostream *OutputFile; unsigned CurrentIncludeDepth; bool HasProcessedPredefines; bool OwnsOutputFile; @@ -26,7 +26,7 @@ class HeaderIncludesCallback : public PPCallbacks { public: HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_, - llvm::raw_ostream *OutputFile_, bool OwnsOutputFile_, + raw_ostream *OutputFile_, bool OwnsOutputFile_, bool ShowDepth_) : SM(PP->getSourceManager()), OutputFile(OutputFile_), CurrentIncludeDepth(0), HasProcessedPredefines(false), @@ -39,13 +39,14 @@ public: } virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType); + SrcMgr::CharacteristicKind FileType, + FileID PrevFID); }; } void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders, - llvm::StringRef OutputPath, bool ShowDepth) { - llvm::raw_ostream *OutputFile = &llvm::errs(); + StringRef OutputPath, bool ShowDepth) { + raw_ostream *OutputFile = &llvm::errs(); bool OwnsOutputFile = false; // Open the output file, if used. @@ -72,7 +73,8 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders, void HeaderIncludesCallback::FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind NewFileType) { + SrcMgr::CharacteristicKind NewFileType, + FileID PrevFID) { // Unless we are exiting a #include, make sure to skip ahead to the line the // #include directive was at. PresumedLoc UserLoc = SM.getPresumedLoc(Loc); diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp index ae38a19..43b6d4c 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp @@ -56,38 +56,34 @@ class InitHeaderSearch { public: - InitHeaderSearch(HeaderSearch &HS, bool verbose, llvm::StringRef sysroot) + InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot) : Headers(HS), Verbose(verbose), IncludeSysroot(sysroot), IsNotEmptyOrRoot(!(sysroot.empty() || sysroot == "/")) { } /// AddPath - Add the specified path to the specified group list. - void AddPath(const llvm::Twine &Path, IncludeDirGroup Group, + void AddPath(const Twine &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot = false); /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu /// libstdc++. - void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, - llvm::StringRef ArchDir, - llvm::StringRef Dir32, - llvm::StringRef Dir64, + void AddGnuCPlusPlusIncludePaths(StringRef Base, + StringRef ArchDir, + StringRef Dir32, + StringRef Dir64, const llvm::Triple &triple); /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to support a MinGW /// libstdc++. - void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, - llvm::StringRef Arch, - llvm::StringRef Version); + void AddMinGWCPlusPlusIncludePaths(StringRef Base, + StringRef Arch, + StringRef Version); /// AddMinGW64CXXPaths - Add the necessary paths to support /// libstdc++ of x86_64-w64-mingw32 aka mingw-w64. - void AddMinGW64CXXPaths(llvm::StringRef Base, - llvm::StringRef Version); - - /// AddDelimitedPaths - Add a list of paths delimited by the system PATH - /// separator. The processing follows that of the CPATH variable for gcc. - void AddDelimitedPaths(llvm::StringRef String); + void AddMinGW64CXXPaths(StringRef Base, + StringRef Version); // AddDefaultCIncludePaths - Add paths that should always be searched. void AddDefaultCIncludePaths(const llvm::Triple &triple, @@ -100,9 +96,9 @@ public: /// AddDefaultSystemIncludePaths - Adds the default system include paths so /// that e.g. stdio.h is found. - void AddDefaultSystemIncludePaths(const LangOptions &Lang, - const llvm::Triple &triple, - const HeaderSearchOptions &HSOpts); + void AddDefaultIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple, + const HeaderSearchOptions &HSOpts); /// Realize - Merges all search path lists into one list and send it to /// HeaderSearch. @@ -111,7 +107,7 @@ public: } // end anonymous namespace. -void InitHeaderSearch::AddPath(const llvm::Twine &Path, +void InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot) { @@ -120,7 +116,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, // Compute the actual path, taking into consideration -isysroot. llvm::SmallString<256> MappedPathStorage; - llvm::StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); + StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); // Handle isysroot. if ((Group == System || Group == CXXSystem) && !IgnoreSysRoot && @@ -138,7 +134,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, // Compute the DirectoryLookup type. SrcMgr::CharacteristicKind Type; - if (Group == Quoted || Group == Angled) + if (Group == Quoted || Group == Angled || Group == IndexHeaderMap) Type = SrcMgr::C_User; else if (isCXXAware) Type = SrcMgr::C_System; @@ -160,7 +156,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, 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))); + isUserSupplied, Group == IndexHeaderMap))); return; } } @@ -171,30 +167,10 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, << MappedPathStr << "\"\n"; } - -void InitHeaderSearch::AddDelimitedPaths(llvm::StringRef at) { - if (at.empty()) // Empty string should not add '.' path. - return; - - llvm::StringRef::size_type delim; - while ((delim = at.find(llvm::sys::PathSeparator)) != llvm::StringRef::npos) { - if (delim == 0) - AddPath(".", Angled, false, true, false); - else - AddPath(at.substr(0, delim), Angled, false, true, false); - at = at.substr(delim + 1); - } - - if (at.empty()) - AddPath(".", Angled, false, true, false); - else - AddPath(at, Angled, false, true, false); -} - -void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, - llvm::StringRef ArchDir, - llvm::StringRef Dir32, - llvm::StringRef Dir64, +void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base, + StringRef ArchDir, + StringRef Dir32, + StringRef Dir64, const llvm::Triple &triple) { // Add the base dir AddPath(Base, CXXSystem, true, false, false); @@ -211,9 +187,9 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, AddPath(Base + "/backward", CXXSystem, true, false, false); } -void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, - llvm::StringRef Arch, - llvm::StringRef Version) { +void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base, + StringRef Arch, + StringRef Version) { AddPath(Base + "/" + Arch + "/" + Version + "/include/c++", CXXSystem, true, false, false); AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch, @@ -222,8 +198,8 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, CXXSystem, true, false, false); } -void InitHeaderSearch::AddMinGW64CXXPaths(llvm::StringRef Base, - llvm::StringRef Version) { +void InitHeaderSearch::AddMinGW64CXXPaths(StringRef Base, + StringRef Version) { // Assumes Base is HeaderSearchOpts' ResourceDir AddPath(Base + "/../../../include/c++/" + Version, CXXSystem, true, false, false); @@ -452,14 +428,16 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { llvm::Triple::OSType os = triple.getOS(); - switch (os) { - case llvm::Triple::FreeBSD: - case llvm::Triple::NetBSD: - break; - default: - // FIXME: temporary hack: hard-coded paths. - AddPath("/usr/local/include", System, true, false, false); - break; + if (HSOpts.UseStandardSystemIncludes) { + switch (os) { + case llvm::Triple::FreeBSD: + case llvm::Triple::NetBSD: + break; + default: + // FIXME: temporary hack: hard-coded paths. + AddPath("/usr/local/include", System, true, false, false); + break; + } } // Builtin includes use #include_next directives and should be positioned @@ -472,12 +450,17 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true); } + // All remaining additions are for system include directories, early exit if + // we aren't using them. + if (!HSOpts.UseStandardSystemIncludes) + return; + // Add dirs specified via 'configure --with-c-include-dirs'. - llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS); + StringRef CIncludeDirs(C_INCLUDE_DIRS); if (CIncludeDirs != "") { - llvm::SmallVector<llvm::StringRef, 5> dirs; + SmallVector<StringRef, 5> dirs; CIncludeDirs.split(dirs, ":"); - for (llvm::SmallVectorImpl<llvm::StringRef>::iterator i = dirs.begin(); + for (SmallVectorImpl<StringRef>::iterator i = dirs.begin(); i != dirs.end(); ++i) AddPath(*i, System, false, false, false); @@ -605,9 +588,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, void InitHeaderSearch:: AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { llvm::Triple::OSType os = triple.getOS(); - llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT); + StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT); if (CxxIncludeRoot != "") { - llvm::StringRef CxxIncludeArch(CXX_INCLUDE_ARCH); + StringRef CxxIncludeArch(CXX_INCLUDE_ARCH); if (CxxIncludeArch == "") AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(), CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, @@ -745,7 +728,12 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp //===------------------------------------------------------------------===// // Redhat based distros. //===------------------------------------------------------------------===// - // Fedora 15 + // Fedora 15 (GCC 4.6.1) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.1", + "i686-redhat-linux", "", "", triple); + // Fedora 15 (GCC 4.6.0) AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", "x86_64-redhat-linux", "32", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", @@ -848,6 +836,17 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", "x86_64-unknown-linux-gnu", "", "", triple); + // Slackware gcc 4.5.2 (13.37) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.2", + "i486-slackware-linux", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.2", + "x86_64-slackware-linux", "", "", triple); + // Slackware gcc 4.5.3 (-current) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.3", + "i486-slackware-linux", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.3", + "x86_64-slackware-linux", "", "", triple); + // Gentoo x86 gcc 4.5.2 AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/i686-pc-linux-gnu/4.5.2/include/g++-v4", @@ -897,6 +896,10 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3/include/g++-v4", "x86_64-pc-linux-gnu", "32", "", triple); + // Gentoo amd64 gcc 4.3.4 + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/include/g++-v4", + "x86_64-pc-linux-gnu", "", "", triple); // Gentoo amd64 gcc 4.3.2 AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/include/g++-v4", @@ -947,32 +950,53 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp } } -void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, - const llvm::Triple &triple, +void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { - if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes) { - if (HSOpts.UseLibcxx) + if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes && + HSOpts.UseStandardSystemIncludes) { + if (HSOpts.UseLibcxx) { + if (triple.isOSDarwin()) { + // On Darwin, libc++ may be installed alongside the compiler in + // lib/c++/v1. + llvm::sys::Path P(HSOpts.ResourceDir); + if (!P.isEmpty()) { + P.eraseComponent(); // Remove version from foo/lib/clang/version + P.eraseComponent(); // Remove clang from foo/lib/clang + + // Get foo/lib/c++/v1 + P.appendComponent("c++"); + P.appendComponent("v1"); + AddPath(P.str(), CXXSystem, true, false, false, true); + } + } + AddPath("/usr/include/c++/v1", CXXSystem, true, false, false); - else + } else { AddDefaultCPlusPlusIncludePaths(triple, HSOpts); + } } AddDefaultCIncludePaths(triple, HSOpts); // Add the default framework include paths on Darwin. - if (triple.isOSDarwin()) { - AddPath("/System/Library/Frameworks", System, true, false, true); - AddPath("/Library/Frameworks", System, true, false, true); + if (HSOpts.UseStandardSystemIncludes) { + if (triple.isOSDarwin()) { + AddPath("/System/Library/Frameworks", System, true, false, true); + AddPath("/Library/Frameworks", System, true, false, true); + } } } /// RemoveDuplicates - If there are duplicate directory entries in the specified -/// search list, remove the later (dead) ones. -static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, - unsigned First, bool Verbose) { +/// search list, remove the later (dead) ones. Returns the number of non-system +/// headers removed, which is used to update NumAngled. +static unsigned RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, + unsigned First, bool Verbose) { llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs; llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs; llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps; + unsigned NonSystemRemoved = 0; for (unsigned i = First; i != SearchList.size(); ++i) { unsigned DirToRemove = i; @@ -1039,12 +1063,15 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, llvm::errs() << " as it is a non-system directory that duplicates " << "a system directory\n"; } + if (DirToRemove != i) + ++NonSystemRemoved; // This is reached if the current entry is a duplicate. Remove the // DirToRemove (usually the current dir). SearchList.erase(SearchList.begin()+DirToRemove); --i; } + return NonSystemRemoved; } @@ -1065,7 +1092,7 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { for (path_iterator it = IncludePath.begin(), ie = IncludePath.end(); it != ie; ++it) { - if (it->first == Angled) + if (it->first == Angled || it->first == IndexHeaderMap) SearchList.push_back(it->second); } @@ -1074,7 +1101,11 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { for (path_iterator it = IncludePath.begin(), ie = IncludePath.end(); it != ie; ++it) { - if (it->first == System || (Lang.CPlusPlus && it->first == CXXSystem)) + if (it->first == System || + (!Lang.ObjC1 && !Lang.CPlusPlus && it->first == CSystem) || + (/*FIXME !Lang.ObjC1 && */Lang.CPlusPlus && it->first == CXXSystem) || + (Lang.ObjC1 && !Lang.CPlusPlus && it->first == ObjCSystem) || + (Lang.ObjC1 && Lang.CPlusPlus && it->first == ObjCXXSystem)) SearchList.push_back(it->second); } @@ -1087,7 +1118,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { // Remove duplicates across both the Angled and System directories. GCC does // this and failing to remove duplicates across these two groups breaks // #include_next. - RemoveDuplicates(SearchList, NumQuoted, Verbose); + unsigned NonSystemRemoved = RemoveDuplicates(SearchList, NumQuoted, Verbose); + NumAngled -= NonSystemRemoved; bool DontSearchCurDir = false; // TODO: set to true if -I- is set? Headers.SetSearchPaths(SearchList, NumQuoted, NumAngled, DontSearchCurDir); @@ -1127,19 +1159,7 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, E.IgnoreSysRoot); } - // Add entries from CPATH and friends. - Init.AddDelimitedPaths(HSOpts.EnvIncPath); - if (Lang.CPlusPlus && Lang.ObjC1) - Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath); - else if (Lang.CPlusPlus) - Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath); - else if (Lang.ObjC1) - Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath); - else - Init.AddDelimitedPaths(HSOpts.CEnvIncPath); - - if (HSOpts.UseStandardIncludes) - Init.AddDefaultSystemIncludePaths(Lang, Triple, HSOpts); + Init.AddDefaultIncludePaths(Lang, Triple, HSOpts); Init.Realize(Lang); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp index 9428cd5..6f49ec4 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp @@ -30,15 +30,15 @@ using namespace clang; // Append a #define line to Buf for Macro. Macro should be of the form XXX, // in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit // "#define XXX Y z W". To get a #define with no value, use "XXX=". -static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro, - Diagnostic &Diags) { - std::pair<llvm::StringRef, llvm::StringRef> MacroPair = Macro.split('='); - llvm::StringRef MacroName = MacroPair.first; - llvm::StringRef MacroBody = MacroPair.second; +static void DefineBuiltinMacro(MacroBuilder &Builder, StringRef Macro, + DiagnosticsEngine &Diags) { + std::pair<StringRef, StringRef> MacroPair = Macro.split('='); + StringRef MacroName = MacroPair.first; + StringRef MacroBody = MacroPair.second; if (MacroName.size() != Macro.size()) { // Per GCC -D semantics, the macro ends at \n if it exists. - llvm::StringRef::size_type End = MacroBody.find_first_of("\n\r"); - if (End != llvm::StringRef::npos) + StringRef::size_type End = MacroBody.find_first_of("\n\r"); + if (End != StringRef::npos) Diags.Report(diag::warn_fe_macro_contains_embedded_newline) << MacroName; Builder.defineMacro(MacroName, MacroBody.substr(0, End)); @@ -48,7 +48,7 @@ static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro, } } -std::string clang::NormalizeDashIncludePath(llvm::StringRef File, +std::string clang::NormalizeDashIncludePath(StringRef File, FileManager &FileMgr) { // Implicit include paths should be resolved relative to the current // working directory first, and then use the regular header search @@ -70,17 +70,17 @@ std::string clang::NormalizeDashIncludePath(llvm::StringRef File, /// AddImplicitInclude - Add an implicit #include of the specified file to the /// predefines buffer. -static void AddImplicitInclude(MacroBuilder &Builder, llvm::StringRef File, +static void AddImplicitInclude(MacroBuilder &Builder, StringRef File, FileManager &FileMgr) { Builder.append("#include \"" + - llvm::Twine(NormalizeDashIncludePath(File, FileMgr)) + "\""); + Twine(NormalizeDashIncludePath(File, FileMgr)) + "\""); } static void AddImplicitIncludeMacros(MacroBuilder &Builder, - llvm::StringRef File, + StringRef File, FileManager &FileMgr) { Builder.append("#__include_macros \"" + - llvm::Twine(NormalizeDashIncludePath(File, FileMgr)) + "\""); + Twine(NormalizeDashIncludePath(File, FileMgr)) + "\""); // Marker token to stop the __include_macros fetch loop. Builder.append("##"); // ##? } @@ -88,7 +88,7 @@ static void AddImplicitIncludeMacros(MacroBuilder &Builder, /// AddImplicitIncludePTH - Add an implicit #include using the original file /// used to generate a PTH cache. static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP, - llvm::StringRef ImplicitIncludePTH) { + StringRef ImplicitIncludePTH) { PTHManager *P = PP.getPTHManager(); // Null check 'P' in the corner case where it couldn't be created. const char *OriginalFile = P ? P->getOriginalSourceFile() : 0; @@ -120,7 +120,7 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal, return IEEEQuadVal; } -static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix, +static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix, const llvm::fltSemantics *Sem) { const char *DenormMin, *Epsilon, *Max, *Min; DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324", @@ -153,27 +153,27 @@ static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix, Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin); Builder.defineMacro(DefPrefix + "HAS_DENORM__"); - Builder.defineMacro(DefPrefix + "DIG__", llvm::Twine(Digits)); - Builder.defineMacro(DefPrefix + "EPSILON__", llvm::Twine(Epsilon)); + Builder.defineMacro(DefPrefix + "DIG__", Twine(Digits)); + Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon)); Builder.defineMacro(DefPrefix + "HAS_INFINITY__"); Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__"); - Builder.defineMacro(DefPrefix + "MANT_DIG__", llvm::Twine(MantissaDigits)); + Builder.defineMacro(DefPrefix + "MANT_DIG__", Twine(MantissaDigits)); - Builder.defineMacro(DefPrefix + "MAX_10_EXP__", llvm::Twine(Max10Exp)); - Builder.defineMacro(DefPrefix + "MAX_EXP__", llvm::Twine(MaxExp)); - Builder.defineMacro(DefPrefix + "MAX__", llvm::Twine(Max)); + Builder.defineMacro(DefPrefix + "MAX_10_EXP__", Twine(Max10Exp)); + Builder.defineMacro(DefPrefix + "MAX_EXP__", Twine(MaxExp)); + Builder.defineMacro(DefPrefix + "MAX__", Twine(Max)); - Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+llvm::Twine(Min10Exp)+")"); - Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+llvm::Twine(MinExp)+")"); - Builder.defineMacro(DefPrefix + "MIN__", llvm::Twine(Min)); + Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+Twine(Min10Exp)+")"); + Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+Twine(MinExp)+")"); + Builder.defineMacro(DefPrefix + "MIN__", Twine(Min)); } /// DefineTypeSize - Emit a macro to the predefines buffer that declares a macro /// named MacroName with the max value for a type with width 'TypeWidth' a /// signedness of 'isSigned' and with a value suffix of 'ValSuffix' (e.g. LL). -static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth, - llvm::StringRef ValSuffix, bool isSigned, +static void DefineTypeSize(StringRef MacroName, unsigned TypeWidth, + StringRef ValSuffix, bool isSigned, MacroBuilder &Builder) { llvm::APInt MaxVal = isSigned ? llvm::APInt::getSignedMaxValue(TypeWidth) : llvm::APInt::getMaxValue(TypeWidth); @@ -182,26 +182,26 @@ static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth, /// DefineTypeSize - An overloaded helper that uses TargetInfo to determine /// the width, suffix, and signedness of the given type -static void DefineTypeSize(llvm::StringRef MacroName, TargetInfo::IntType Ty, +static void DefineTypeSize(StringRef MacroName, TargetInfo::IntType Ty, const TargetInfo &TI, MacroBuilder &Builder) { DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty), TI.isTypeSigned(Ty), Builder); } -static void DefineType(const llvm::Twine &MacroName, TargetInfo::IntType Ty, +static void DefineType(const Twine &MacroName, TargetInfo::IntType Ty, MacroBuilder &Builder) { Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty)); } -static void DefineTypeWidth(llvm::StringRef MacroName, TargetInfo::IntType Ty, +static void DefineTypeWidth(StringRef MacroName, TargetInfo::IntType Ty, const TargetInfo &TI, MacroBuilder &Builder) { - Builder.defineMacro(MacroName, llvm::Twine(TI.getTypeWidth(Ty))); + Builder.defineMacro(MacroName, Twine(TI.getTypeWidth(Ty))); } -static void DefineTypeSizeof(llvm::StringRef MacroName, unsigned BitWidth, +static void DefineTypeSizeof(StringRef MacroName, unsigned BitWidth, const TargetInfo &TI, MacroBuilder &Builder) { Builder.defineMacro(MacroName, - llvm::Twine(BitWidth / TI.getCharWidth())); + Twine(BitWidth / TI.getCharWidth())); } static void DefineExactWidthIntType(TargetInfo::IntType Ty, @@ -213,81 +213,15 @@ static void DefineExactWidthIntType(TargetInfo::IntType Ty, if (TypeWidth == 64) Ty = TI.getInt64Type(); - DefineType("__INT" + llvm::Twine(TypeWidth) + "_TYPE__", Ty, Builder); + DefineType("__INT" + Twine(TypeWidth) + "_TYPE__", Ty, Builder); - llvm::StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty)); + StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty)); if (!ConstSuffix.empty()) - Builder.defineMacro("__INT" + llvm::Twine(TypeWidth) + "_C_SUFFIX__", + Builder.defineMacro("__INT" + Twine(TypeWidth) + "_C_SUFFIX__", ConstSuffix); } /// \brief Add definitions required for a smooth interaction between -/// Objective-C++ automatic reference counting and libc++. -static void AddObjCXXARCLibcxxDefines(const LangOptions &LangOpts, - MacroBuilder &Builder) { - Builder.defineMacro("_LIBCPP_PREDEFINED_OBJC_ARC_ADDRESSOF"); - - std::string Result; - { - // Provide overloads of the function std::__1::addressof() that accept - // references to lifetime-qualified objects. libc++'s (more general) - // std::__1::addressof() template fails to instantiate with such types, - // because it attempts to convert the object to a char& before - // dereferencing. - llvm::raw_string_ostream Out(Result); - - Out << "#pragma clang diagnostic push\n" - << "#pragma clang diagnostic ignored \"-Wc++0x-extensions\"\n" - << "namespace std { inline namespace __1 {\n" - << "\n"; - - Out << "template <class _Tp>\n" - << "inline __attribute__ ((__visibility__(\"hidden\"), " - << "__always_inline__))\n" - << "__attribute__((objc_ownership(strong))) _Tp*\n" - << "addressof(__attribute__((objc_ownership(strong))) _Tp& __x) {\n" - << " return &__x;\n" - << "}\n" - << "\n"; - - if (LangOpts.ObjCRuntimeHasWeak) { - Out << "template <class _Tp>\n" - << "inline __attribute__ ((__visibility__(\"hidden\")," - << "__always_inline__))\n" - << "__attribute__((objc_ownership(weak))) _Tp*\n" - << "addressof(__attribute__((objc_ownership(weak))) _Tp& __x) {\n" - << " return &__x;\n" - << "};\n" - << "\n"; - } - - Out << "template <class _Tp>\n" - << "inline __attribute__ ((__visibility__(\"hidden\")," - << "__always_inline__))\n" - << "__attribute__((objc_ownership(autoreleasing))) _Tp*\n" - << "addressof(__attribute__((objc_ownership(autoreleasing))) _Tp& __x) " - << "{\n" - << " return &__x;\n" - << "}\n" - << "\n"; - - Out << "template <class _Tp>\n" - << "inline __attribute__ ((__visibility__(\"hidden\"), " - << "__always_inline__))\n" - << "__unsafe_unretained _Tp* addressof(__unsafe_unretained _Tp& __x)" - << " {\n" - << " return &__x;\n" - << "}\n"; - - Out << "\n" - << "} }\n" - << "#pragma clang diagnostic pop\n" - << "\n"; - } - Builder.append(Result); -} - -/// \brief Add definitions required for a smooth interaction between /// Objective-C++ automated reference counting and libstdc++ (4.2). static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, MacroBuilder &Builder) { @@ -344,7 +278,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, const LangOptions &LangOpts, const FrontendOptions &FEOpts, MacroBuilder &Builder) { - if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP) + if (!LangOpts.MicrosoftExt && !LangOpts.TraditionalCPP) Builder.defineMacro("__STDC__"); if (LangOpts.Freestanding) Builder.defineMacro("__STDC_HOSTED__", "0"); @@ -412,7 +346,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // checks that it is necessary to report 4.2.1 (the base GCC version we claim // compatibility with) first. Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible " + - llvm::Twine(getClangFullCPPVersion()) + "\""); + Twine(getClangFullCPPVersion()) + "\""); // Initialize language-specific preprocessor defines. @@ -426,10 +360,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.ObjC1) { if (LangOpts.ObjCNonFragileABI) { Builder.defineMacro("__OBJC2__"); - Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS"); + + if (LangOpts.ObjCExceptions) + Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS"); } - if (LangOpts.getGCMode() != LangOptions::NonGC) + if (LangOpts.getGC() != LangOptions::NonGC) Builder.defineMacro("__OBJC_GC__"); if (LangOpts.NeXTRuntime) @@ -452,7 +388,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__BLOCKS__"); } - if (LangOpts.Exceptions) + if (LangOpts.CXXExceptions) Builder.defineMacro("__EXCEPTIONS"); if (LangOpts.RTTI) Builder.defineMacro("__GXX_RTTI"); @@ -468,7 +404,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__private_extern__", "extern"); } - if (LangOpts.Microsoft) { + if (LangOpts.MicrosoftExt) { // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however // VC++ appears to only like __FUNCTION__. Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__"); @@ -546,7 +482,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Define a __POINTER_WIDTH__ macro for stdint.h. Builder.defineMacro("__POINTER_WIDTH__", - llvm::Twine((int)TI.getPointerWidth(0))); + Twine((int)TI.getPointerWidth(0))); if (!LangOpts.CharIsSigned) Builder.defineMacro("__CHAR_UNSIGNED__"); @@ -555,7 +491,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__WINT_UNSIGNED__"); // Define exact-width integer types for stdint.h - Builder.defineMacro("__INT" + llvm::Twine(TI.getCharWidth()) + "_TYPE__", + Builder.defineMacro("__INT" + Twine(TI.getCharWidth()) + "_TYPE__", "char"); if (TI.getShortWidth() > TI.getCharWidth()) @@ -589,19 +525,19 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__NO_INLINE__"); if (unsigned PICLevel = LangOpts.PICLevel) { - Builder.defineMacro("__PIC__", llvm::Twine(PICLevel)); - Builder.defineMacro("__pic__", llvm::Twine(PICLevel)); + Builder.defineMacro("__PIC__", Twine(PICLevel)); + Builder.defineMacro("__pic__", Twine(PICLevel)); } // Macros to control C99 numerics and <float.h> Builder.defineMacro("__FLT_EVAL_METHOD__", "0"); Builder.defineMacro("__FLT_RADIX__", "2"); int Dig = PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36); - Builder.defineMacro("__DECIMAL_DIG__", llvm::Twine(Dig)); + Builder.defineMacro("__DECIMAL_DIG__", Twine(Dig)); - if (LangOpts.getStackProtectorMode() == LangOptions::SSPOn) + if (LangOpts.getStackProtector() == LangOptions::SSPOn) Builder.defineMacro("__SSP__"); - else if (LangOpts.getStackProtectorMode() == LangOptions::SSPReq) + else if (LangOpts.getStackProtector() == LangOptions::SSPReq) Builder.defineMacro("__SSP_ALL__", "2"); if (FEOpts.ProgramAction == frontend::RewriteObjC) @@ -629,7 +565,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Initialize the remapping of files to alternative contents, e.g., // those specified through other files. -static void InitializeFileRemapping(Diagnostic &Diags, +static void InitializeFileRemapping(DiagnosticsEngine &Diags, SourceManager &SourceMgr, FileManager &FileMgr, const PreprocessorOptions &InitOpts) { @@ -705,6 +641,10 @@ void clang::InitializePreprocessor(Preprocessor &PP, InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), PP.getFileManager(), InitOpts); + // Specify whether the preprocessor should replace #include/#import with + // module imports when plausible. + PP.setAutoModuleImport(InitOpts.AutoModuleImport); + // Emit line markers for various builtin sections of the file. We don't do // this in asm preprocessor mode, because "# 4" is not a line marker directive // in this mode. @@ -720,10 +660,7 @@ void clang::InitializePreprocessor(Preprocessor &PP, if (LangOpts.ObjC1 && LangOpts.CPlusPlus && LangOpts.ObjCAutoRefCount) { switch (InitOpts.ObjCXXARCStandardLibrary) { case ARCXX_nolib: - break; - - case ARCXX_libcxx: - AddObjCXXARCLibcxxDefines(LangOpts, Builder); + case ARCXX_libcxx: break; case ARCXX_libstdcxx: @@ -778,7 +715,7 @@ void clang::InitializePreprocessor(Preprocessor &PP, // Copy PredefinedBuffer into the Preprocessor. PP.setPredefines(Predefines.str()); - + // Initialize the header search object. ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts, PP.getLangOptions(), diff --git a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp index af1721d..abb521b 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp @@ -29,7 +29,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) { } } -const LangStandard *LangStandard::getLangStandardForName(llvm::StringRef Name) { +const LangStandard *LangStandard::getLangStandardForName(StringRef Name) { Kind K = llvm::StringSwitch<Kind>(Name) #define LANGSTANDARD(id, name, desc, features) \ .Case(name, lang_##id) diff --git a/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp index 78eb1b2..8b585be 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp @@ -14,7 +14,7 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; -LogDiagnosticPrinter::LogDiagnosticPrinter(llvm::raw_ostream &os, +LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os, const DiagnosticOptions &diags, bool _OwnsOutputStream) : OS(os), LangOpts(0), DiagOpts(&diags), @@ -26,15 +26,30 @@ LogDiagnosticPrinter::~LogDiagnosticPrinter() { delete &OS; } -static llvm::StringRef getLevelName(Diagnostic::Level Level) { +static StringRef getLevelName(DiagnosticsEngine::Level Level) { switch (Level) { default: return "<unknown>"; - case Diagnostic::Ignored: return "ignored"; - case Diagnostic::Note: return "note"; - case Diagnostic::Warning: return "warning"; - case Diagnostic::Error: return "error"; - case Diagnostic::Fatal: return "fatal error"; + case DiagnosticsEngine::Ignored: return "ignored"; + case DiagnosticsEngine::Note: return "note"; + case DiagnosticsEngine::Warning: return "warning"; + case DiagnosticsEngine::Error: return "error"; + case DiagnosticsEngine::Fatal: return "fatal error"; + } +} + +// Escape XML characters inside the raw string. +static void emitString(llvm::raw_svector_ostream &OS, const StringRef Raw) { + for (StringRef::iterator I = Raw.begin(), E = Raw.end(); I != E; ++I) { + char c = *I; + switch (c) { + default: OS << c; break; + case '&': OS << "&"; break; + case '<': OS << "<"; break; + case '>': OS << ">"; break; + case '\'': OS << "'"; break; + case '\"': OS << """; break; + } } } @@ -42,9 +57,9 @@ void LogDiagnosticPrinter::EndSourceFile() { // We emit all the diagnostics in EndSourceFile. However, we don't emit any // entry if no diagnostics were present. // - // Note that DiagnosticClient has no "end-of-compilation" callback, so we will - // miss any diagnostics which are emitted after and outside the translation - // unit processing. + // Note that DiagnosticConsumer has no "end-of-compilation" callback, so we + // will miss any diagnostics which are emitted after and outside the + // translation unit processing. if (Entries.empty()) return; @@ -55,11 +70,15 @@ void LogDiagnosticPrinter::EndSourceFile() { OS << "<dict>\n"; if (!MainFilename.empty()) { OS << " <key>main-file</key>\n" - << " <string>" << MainFilename << "</string>\n"; + << " <string>"; + emitString(OS, MainFilename); + OS << "</string>\n"; } if (!DwarfDebugFlags.empty()) { OS << " <key>dwarf-debug-flags</key>\n" - << " <string>" << DwarfDebugFlags << "</string>\n"; + << " <string>"; + emitString(OS, DwarfDebugFlags); + OS << "</string>\n"; } OS << " <key>diagnostics</key>\n"; OS << " <array>\n"; @@ -68,10 +87,14 @@ void LogDiagnosticPrinter::EndSourceFile() { OS << " <dict>\n"; OS << " <key>level</key>\n" - << " <string>" << getLevelName(DE.DiagnosticLevel) << "</string>\n"; + << " <string>"; + emitString(OS, getLevelName(DE.DiagnosticLevel)); + OS << "</string>\n"; if (!DE.Filename.empty()) { OS << " <key>filename</key>\n" - << " <string>" << DE.Filename << "</string>\n"; + << " <string>"; + emitString(OS, DE.Filename); + OS << "</string>\n"; } if (DE.Line != 0) { OS << " <key>line</key>\n" @@ -83,7 +106,9 @@ void LogDiagnosticPrinter::EndSourceFile() { } if (!DE.Message.empty()) { OS << " <key>message</key>\n" - << " <string>" << DE.Message << "</string>\n"; + << " <string>"; + emitString(OS, DE.Message); + OS << "</string>\n"; } OS << " </dict>\n"; } @@ -93,10 +118,10 @@ void LogDiagnosticPrinter::EndSourceFile() { this->OS << OS.str(); } -void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) { +void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) { // Default implementation (Warnings/errors count). - DiagnosticClient::HandleDiagnostic(Level, Info); + DiagnosticConsumer::HandleDiagnostic(Level, Info); // Initialize the main file name, if we haven't already fetched it. if (MainFilename.empty() && Info.hasSourceManager()) { @@ -144,3 +169,9 @@ void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, // Record the diagnostic entry. Entries.push_back(DE); } + +DiagnosticConsumer * +LogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { + return new LogDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); +} + diff --git a/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp index 5aa65d7..8e746f6 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp @@ -37,7 +37,7 @@ public: virtual void TypeRead(serialization::TypeIdx Idx, QualType T); virtual void DeclRead(serialization::DeclID ID, const Decl *D); virtual void SelectorRead(serialization::SelectorID iD, Selector Sel); - virtual void MacroDefinitionRead(serialization::MacroID, + virtual void MacroDefinitionRead(serialization::PreprocessedEntityID, MacroDefinition *MD); private: std::vector<ASTDeserializationListener*> Listeners; @@ -79,7 +79,7 @@ void MultiplexASTDeserializationListener::SelectorRead( } void MultiplexASTDeserializationListener::MacroDefinitionRead( - serialization::MacroID ID, MacroDefinition *MD) { + serialization::PreprocessedEntityID ID, MacroDefinition *MD) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->MacroDefinitionRead(ID, MD); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp index c892960..8a61f96 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -33,7 +33,7 @@ using namespace clang; /// PrintMacroDefinition - Print a macro definition in a form that will be /// properly accepted back as a definition. static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, - Preprocessor &PP, llvm::raw_ostream &OS) { + Preprocessor &PP, raw_ostream &OS) { OS << "#define " << II.getName(); if (MI.isFunctionLike()) { @@ -83,7 +83,7 @@ class PrintPPOutputPPCallbacks : public PPCallbacks { SourceManager &SM; TokenConcatenation ConcatInfo; public: - llvm::raw_ostream &OS; + raw_ostream &OS; private: unsigned CurLine; @@ -96,7 +96,7 @@ private: bool DumpDefines; bool UseLineDirective; public: - PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os, + PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream &os, bool lineMarkers, bool defines) : PP(pp), SM(PP.getSourceManager()), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers), @@ -109,7 +109,7 @@ public: Initialized = false; // If we're in microsoft mode, use normal #line instead of line markers. - UseLineDirective = PP.getLangOptions().Microsoft; + UseLineDirective = PP.getLangOptions().MicrosoftExt; } void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; } @@ -118,17 +118,18 @@ public: bool StartNewLineIfNeeded(); virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind FileType); + SrcMgr::CharacteristicKind FileType, + FileID PrevFID); virtual void Ident(SourceLocation Loc, const std::string &str); virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, const std::string &Str); - virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str); + virtual void PragmaMessage(SourceLocation Loc, StringRef Str); virtual void PragmaDiagnosticPush(SourceLocation Loc, - llvm::StringRef Namespace); + StringRef Namespace); virtual void PragmaDiagnosticPop(SourceLocation Loc, - llvm::StringRef Namespace); - virtual void PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace, - diag::Mapping Map, llvm::StringRef Str); + StringRef Namespace); + virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Mapping Map, StringRef Str); bool HandleFirstTokOnLine(Token &Tok); bool MoveToLine(SourceLocation Loc) { @@ -235,7 +236,8 @@ bool PrintPPOutputPPCallbacks::StartNewLineIfNeeded() { /// position. void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, - SrcMgr::CharacteristicKind NewFileType) { + SrcMgr::CharacteristicKind NewFileType, + FileID PrevFID) { // Unless we are exiting a #include, make sure to skip ahead to the line the // #include directive was at. SourceManager &SourceMgr = SM; @@ -346,7 +348,7 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc, } void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, - llvm::StringRef Str) { + StringRef Str) { MoveToLine(Loc); OS << "#pragma message("; @@ -369,22 +371,22 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, } void PrintPPOutputPPCallbacks:: -PragmaDiagnosticPush(SourceLocation Loc, llvm::StringRef Namespace) { +PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) { MoveToLine(Loc); OS << "#pragma " << Namespace << " diagnostic push"; EmittedTokensOnThisLine = true; } void PrintPPOutputPPCallbacks:: -PragmaDiagnosticPop(SourceLocation Loc, llvm::StringRef Namespace) { +PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) { MoveToLine(Loc); OS << "#pragma " << Namespace << " diagnostic pop"; EmittedTokensOnThisLine = true; } void PrintPPOutputPPCallbacks:: -PragmaDiagnostic(SourceLocation Loc, llvm::StringRef Namespace, - diag::Mapping Map, llvm::StringRef Str) { +PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Mapping Map, StringRef Str) { MoveToLine(Loc); OS << "#pragma " << Namespace << " diagnostic "; switch (Map) { @@ -419,7 +421,7 @@ bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) { // Print out space characters so that the first token on a line is // indented for easy reading. - unsigned ColNo = SM.getInstantiationColumnNumber(Tok.getLocation()); + unsigned ColNo = SM.getExpansionColumnNumber(Tok.getLocation()); // This hack prevents stuff like: // #define HASH # @@ -491,7 +493,7 @@ struct UnknownPragmaHandler : public PragmaHandler { static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, PrintPPOutputPPCallbacks *Callbacks, - llvm::raw_ostream &OS) { + raw_ostream &OS) { char Buffer[256]; Token PrevPrevTok, PrevTok; PrevPrevTok.startToken(); @@ -550,7 +552,7 @@ static int MacroIDCompare(const void* a, const void* b) { return LHS->first->getName().compare(RHS->first->getName()); } -static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { +static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) { // Ignore unknown pragmas. PP.AddPragmaHandler(new EmptyPragmaHandler()); @@ -562,7 +564,7 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { do PP.Lex(Tok); while (Tok.isNot(tok::eof)); - llvm::SmallVector<id_macro_pair, 128> + SmallVector<id_macro_pair, 128> MacrosByID(PP.macro_begin(), PP.macro_end()); llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare); @@ -578,7 +580,7 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { /// DoPrintPreprocessedInput - This implements -E mode. /// -void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, +void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts) { // Show macros with no output is handled specially. if (!Opts.ShowCPP) { diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp index 069c86d..f8ea9f1 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp @@ -13,39 +13,48 @@ #include "clang/Frontend/TextDiagnosticBuffer.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; /// HandleDiagnostic - Store the errors, warnings, and notes that are /// reported. /// -void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) { +void TextDiagnosticBuffer::HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) { // Default implementation (Warnings/errors count). - DiagnosticClient::HandleDiagnostic(Level, Info); + DiagnosticConsumer::HandleDiagnostic(Level, Info); llvm::SmallString<100> Buf; Info.FormatDiagnostic(Buf); switch (Level) { - default: assert(0 && "Diagnostic not handled during diagnostic buffering!"); - case Diagnostic::Note: + default: llvm_unreachable( + "Diagnostic not handled during diagnostic buffering!"); + case DiagnosticsEngine::Note: Notes.push_back(std::make_pair(Info.getLocation(), Buf.str())); break; - case Diagnostic::Warning: + case DiagnosticsEngine::Warning: Warnings.push_back(std::make_pair(Info.getLocation(), Buf.str())); break; - case Diagnostic::Error: - case Diagnostic::Fatal: + case DiagnosticsEngine::Error: + case DiagnosticsEngine::Fatal: Errors.push_back(std::make_pair(Info.getLocation(), Buf.str())); break; } } -void TextDiagnosticBuffer::FlushDiagnostics(Diagnostic &Diags) const { +void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const { // FIXME: Flush the diagnostics in order. for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, it->second.c_str())); + Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, + it->second.c_str())); for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(Diagnostic::Warning,it->second.c_str())); + Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Warning, + it->second.c_str())); for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(Diagnostic::Note, it->second.c_str())); + Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note, + it->second.c_str())); +} + +DiagnosticConsumer *TextDiagnosticBuffer::clone(DiagnosticsEngine &) const { + return new TextDiagnosticBuffer(); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp index e49e19a..10e7238 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -18,29 +18,29 @@ #include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" #include <algorithm> using namespace clang; -static const enum llvm::raw_ostream::Colors noteColor = - llvm::raw_ostream::BLACK; -static const enum llvm::raw_ostream::Colors fixitColor = - llvm::raw_ostream::GREEN; -static const enum llvm::raw_ostream::Colors caretColor = - llvm::raw_ostream::GREEN; -static const enum llvm::raw_ostream::Colors warningColor = - llvm::raw_ostream::MAGENTA; -static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED; -static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED; +static const enum raw_ostream::Colors noteColor = + raw_ostream::BLACK; +static const enum raw_ostream::Colors fixitColor = + raw_ostream::GREEN; +static const enum raw_ostream::Colors caretColor = + raw_ostream::GREEN; +static const enum raw_ostream::Colors warningColor = + raw_ostream::MAGENTA; +static const enum raw_ostream::Colors errorColor = raw_ostream::RED; +static const enum raw_ostream::Colors fatalColor = raw_ostream::RED; // Used for changing only the bold attribute. -static const enum llvm::raw_ostream::Colors savedColor = - llvm::raw_ostream::SAVEDCOLOR; +static const enum raw_ostream::Colors savedColor = + raw_ostream::SAVEDCOLOR; /// \brief Number of spaces to indent when word-wrapping. const unsigned WordWrapIndentation = 6; -TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os, +TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os, const DiagnosticOptions &diags, bool _OwnsOutputStream) : OS(os), LangOpts(0), DiagOpts(&diags), @@ -53,105 +53,52 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() { delete &OS; } -void TextDiagnosticPrinter::PrintIncludeStack(Diagnostic::Level Level, - SourceLocation Loc, - const SourceManager &SM) { - if (!DiagOpts->ShowNoteIncludeStack && Level == Diagnostic::Note) return; - - if (Loc.isInvalid()) return; +/// \brief Helper to recursivly walk up the include stack and print each layer +/// on the way back down. +static void PrintIncludeStackRecursively(raw_ostream &OS, + const SourceManager &SM, + SourceLocation Loc, + bool ShowLocation) { + if (Loc.isInvalid()) + return; PresumedLoc PLoc = SM.getPresumedLoc(Loc); if (PLoc.isInvalid()) return; - + // Print out the other include frames first. - PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM); + PrintIncludeStackRecursively(OS, SM, PLoc.getIncludeLoc(), ShowLocation); - if (DiagOpts->ShowLocation) + if (ShowLocation) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else OS << "In included file:\n"; } -/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s) -/// any characters in LineNo that intersect the SourceRange. -void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R, - const SourceManager &SM, - unsigned LineNo, FileID FID, - std::string &CaretLine, - const std::string &SourceLine) { - assert(CaretLine.size() == SourceLine.size() && - "Expect a correspondence between source and caret line!"); - if (!R.isValid()) return; - - SourceLocation Begin = SM.getInstantiationLoc(R.getBegin()); - SourceLocation End = SM.getInstantiationLoc(R.getEnd()); - - // If the End location and the start location are the same and are a macro - // location, then the range was something that came from a macro expansion - // or _Pragma. If this is an object-like macro, the best we can do is to - // highlight the range. If this is a function-like macro, we'd also like to - // highlight the arguments. - if (Begin == End && R.getEnd().isMacroID()) - End = SM.getInstantiationRange(R.getEnd()).second; - - unsigned StartLineNo = SM.getInstantiationLineNumber(Begin); - if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) - return; // No intersection. - - unsigned EndLineNo = SM.getInstantiationLineNumber(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.getInstantiationColumnNumber(Begin); - if (StartColNo) --StartColNo; // Zero base the col #. - } - - // Compute the column number of the end. - unsigned EndColNo = CaretLine.size(); - if (EndLineNo == LineNo) { - EndColNo = SM.getInstantiationColumnNumber(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(); - } - } +/// \brief Prints an include stack when appropriate for a particular diagnostic +/// level and location. +/// +/// This routine handles all the logic of suppressing particular include stacks +/// (such as those for notes) and duplicate include stacks when repeated +/// warnings occur within the same file. It also handles the logic of +/// customizing the formatting and display of the include stack. +/// +/// \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 TextDiagnosticPrinter::PrintIncludeStack(DiagnosticsEngine::Level Level, + SourceLocation Loc, + const SourceManager &SM) { + // Skip redundant include stacks altogether. + if (LastWarningLoc == Loc) + return; + LastWarningLoc = Loc; - 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 < SourceLine.size() && - (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) - ++StartColNo; - - // Pick the last non-whitespace column. - if (EndColNo > SourceLine.size()) - EndColNo = SourceLine.size(); - while (EndColNo-1 && - (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) - --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??"); - } + if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) + return; - // Fill the range with ~'s. - for (unsigned i = StartColNo; i < EndColNo; ++i) - CaretLine[i] = '~'; + PrintIncludeStackRecursively(OS, SM, Loc, DiagOpts->ShowLocation); } /// \brief When the source code line we want to print is too long for @@ -300,7 +247,7 @@ static SourceLocation skipToMacroArgExpansion(const SourceManager &SM, SourceLocation StartLoc) { for (SourceLocation L = StartLoc; L.isMacroID(); L = SM.getImmediateSpellingLoc(L)) { - if (SM.isMacroArgInstantiation(L)) + if (SM.isMacroArgExpansion(L)) return L; } @@ -317,12 +264,12 @@ static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM, // When we have the location of (part of) an expanded parameter, its spelling // location points to the argument as typed into the macro call, and // therefore is used to locate the macro caller. - if (SM.isMacroArgInstantiation(Loc)) + if (SM.isMacroArgExpansion(Loc)) return SM.getImmediateSpellingLoc(Loc); // Otherwise, the caller of the macro is located where this macro is // expanded (while the spelling is part of the macro definition). - return SM.getImmediateInstantiationRange(Loc).first; + return SM.getImmediateExpansionRange(Loc).first; } /// Gets the location of the immediate macro callee, one level down the stack @@ -334,34 +281,82 @@ static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM, // When we have the location of (part of) an expanded parameter, its // expansion location points to the unexpanded paramater reference within // the macro definition (or callee). - if (SM.isMacroArgInstantiation(Loc)) - return SM.getImmediateInstantiationRange(Loc).first; + if (SM.isMacroArgExpansion(Loc)) + return SM.getImmediateExpansionRange(Loc).first; // Otherwise, the callee of the macro is located where this location was // spelled inside the macro definition. return SM.getImmediateSpellingLoc(Loc); } -void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, - CharSourceRange *Ranges, - unsigned NumRanges, - const SourceManager &SM, - const FixItHint *Hints, - unsigned NumHints, - unsigned Columns, - unsigned OnMacroInst, - unsigned MacroSkipStart, - unsigned MacroSkipEnd) { - assert(LangOpts && "Unexpected diagnostic outside source file processing"); - assert(!Loc.isInvalid() && "must have a valid source location here"); +namespace { - // If this is a macro ID, first emit information about where this was - // expanded (recursively) then emit information about where the token was - // spelled from. - if (!Loc.isFileID()) { - // Whether to suppress printing this macro expansion. - bool Suppressed - = OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd; +/// \brief Class to encapsulate the logic for formatting and printing a textual +/// diagnostic message. +/// +/// This class provides an interface for building and emitting a textual +/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt +/// Hints, and code snippets. In the presence of macros this involves +/// a recursive process, synthesizing notes for each macro expansion. +/// +/// The purpose of this class is to isolate the implementation of printing +/// beautiful text diagnostics from any particular interfaces. The Clang +/// DiagnosticClient is implemented through this class as is diagnostic +/// printing coming out of libclang. +/// +/// A brief worklist: +/// FIXME: Sink the printing of the diagnostic message itself into this class. +/// FIXME: Sink the printing of the include stack into this class. +/// FIXME: Remove the TextDiagnosticPrinter as an input. +/// FIXME: Sink the recursive printing of template instantiations into this +/// class. +class TextDiagnostic { + TextDiagnosticPrinter &Printer; + raw_ostream &OS; + const SourceManager &SM; + const LangOptions &LangOpts; + const DiagnosticOptions &DiagOpts; + +public: + TextDiagnostic(TextDiagnosticPrinter &Printer, + raw_ostream &OS, + const SourceManager &SM, + const LangOptions &LangOpts, + const DiagnosticOptions &DiagOpts) + : Printer(Printer), OS(OS), SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts) { + } + + /// \brief Emit the caret and underlining text. + /// + /// Walks up the macro expansion stack printing the code snippet, caret, + /// underlines and FixItHint display as appropriate at each level. Walk is + /// accomplished by calling itself recursively. + /// + /// FIXME: Remove macro expansion from this routine, it shouldn't be tied to + /// caret diagnostics. + /// FIXME: Break up massive function into logical units. + /// + /// \param Loc The location for this caret. + /// \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 EmitCaret(SourceLocation Loc, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints, + unsigned &MacroDepth, + unsigned OnMacroInst = 0) { + 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()) { + assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!"); + MacroDepth = OnMacroInst; + EmitSnippetAndCaret(Loc, Ranges, Hints); + 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. @@ -370,21 +365,31 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc); // FIXME: Map ranges? - EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, - Hints, NumHints, Columns, - OnMacroInst + 1, MacroSkipStart, MacroSkipEnd); + EmitCaret(OneLevelUp, Ranges, Hints, MacroDepth, OnMacroInst + 1); // Map the location. Loc = getImmediateMacroCalleeLoc(SM, Loc); + unsigned MacroSkipStart = 0, MacroSkipEnd = 0; + if (MacroDepth > DiagOpts.MacroBacktraceLimit) { + MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 + + DiagOpts.MacroBacktraceLimit % 2; + MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2; + } + + // Whether to suppress printing this macro expansion. + bool Suppressed = (OnMacroInst >= MacroSkipStart && + OnMacroInst < MacroSkipEnd); + // Map the ranges. - for (unsigned i = 0; i != NumRanges; ++i) { - CharSourceRange &R = Ranges[i]; - SourceLocation S = R.getBegin(), E = R.getEnd(); - if (S.isMacroID()) - R.setBegin(getImmediateMacroCalleeLoc(SM, S)); - if (E.isMacroID()) - R.setEnd(getImmediateMacroCalleeLoc(SM, E)); + for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) { + SourceLocation Start = I->getBegin(), End = I->getEnd(); + if (Start.isMacroID()) + I->setBegin(getImmediateMacroCalleeLoc(SM, Start)); + if (End.isMacroID()) + I->setEnd(getImmediateMacroCalleeLoc(SM, End)); } if (!Suppressed) { @@ -398,139 +403,248 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, // If this diagnostic is not in the main file, print out the // "included from" lines. - if (LastWarningLoc != PLoc.getIncludeLoc()) { - LastWarningLoc = PLoc.getIncludeLoc(); - PrintIncludeStack(Diagnostic::Note, LastWarningLoc, SM); - } + Printer.PrintIncludeStack(DiagnosticsEngine::Note, PLoc.getIncludeLoc(), + SM); - if (DiagOpts->ShowLocation) { + if (DiagOpts.ShowLocation) { // Emit the file/line/column that this expansion came from. OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'; - if (DiagOpts->ShowColumn) + if (DiagOpts.ShowColumn) OS << PLoc.getColumn() << ':'; OS << ' '; } OS << "note: expanded from:\n"; - EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, 0, 0, - Columns, OnMacroInst + 1, MacroSkipStart, - MacroSkipEnd); + EmitSnippetAndCaret(Loc, Ranges, ArrayRef<FixItHint>()); return; } - + if (OnMacroInst == MacroSkipStart) { // Tell the user that we've skipped contexts. OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart) << " expansions in backtrace; use -fmacro-backtrace-limit=0 to see " "all)\n"; } - - return; } - - // Decompose the location into a FID/Offset pair. - std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); - FileID FID = LocInfo.first; - unsigned FileOffset = LocInfo.second; - - // Get information about the buffer it points into. - bool Invalid = false; - const char *BufStart = SM.getBufferData(FID, &Invalid).data(); - if (Invalid) - return; - unsigned ColNo = SM.getColumnNumber(FID, FileOffset); - unsigned CaretEndColNo - = ColNo + Lexer::MeasureTokenLength(Loc, SM, *LangOpts); + /// \brief Emit a code snippet and caret line. + /// + /// This routine emits a single line's code snippet and caret line.. + /// + /// \param Loc The location for the caret. + /// \param Ranges The underlined ranges for this code snippet. + /// \param Hints The FixIt hints active for this diagnostic. + void EmitSnippetAndCaret(SourceLocation Loc, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints) { + assert(!Loc.isInvalid() && "must have a valid source location here"); + assert(Loc.isFileID() && "must have a file location here"); + + // Decompose the location into a FID/Offset pair. + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + FileID FID = LocInfo.first; + unsigned FileOffset = LocInfo.second; + + // Get information about the buffer it points into. + bool Invalid = false; + const char *BufStart = SM.getBufferData(FID, &Invalid).data(); + if (Invalid) + 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. + unsigned LineNo = SM.getLineNumber(FID, FileOffset); + unsigned ColNo = SM.getColumnNumber(FID, FileOffset); + unsigned CaretEndColNo + = ColNo + Lexer::MeasureTokenLength(Loc, SM, LangOpts); + + // 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; + + // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past + // the source line length as currently being computed. See + // test/Misc/message-length.c. + CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); + + // Copy the line of code into an std::string for ease of manipulation. + std::string SourceLine(LineStart, LineEnd); + + // Create a line for the caret that is filled with spaces that is the same + // length as the line of source code. + std::string CaretLine(LineEnd-LineStart, ' '); + + // Highlight all of the characters covered by Ranges with ~ characters. + for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) + HighlightRange(*I, LineNo, FID, SourceLine, CaretLine); + + // Next, insert the caret itself. + if (ColNo-1 < CaretLine.size()) + CaretLine[ColNo-1] = '^'; + else + CaretLine.push_back('^'); + + ExpandTabs(SourceLine, CaretLine); + + // If we are in -fdiagnostics-print-source-range-info mode, we are trying + // to produce easily machine parsable output. Add a space before the + // source line and the caret to make it trivial to tell the main diagnostic + // line from what the user is intended to see. + if (DiagOpts.ShowSourceRanges) { + SourceLine = ' ' + SourceLine; + CaretLine = ' ' + CaretLine; + } + std::string FixItInsertionLine = BuildFixItInsertionLine(LineNo, + LineStart, LineEnd, + Hints); - // 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; + // If the source line is too long for our terminal, select only the + // "interesting" source region within that line. + unsigned Columns = DiagOpts.MessageLength; + if (Columns && SourceLine.size() > Columns) + SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, + CaretEndColNo, Columns); - // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past - // the source line length as currently being computed. See - // test/Misc/message-length.c. - CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); + // Finally, remove any blank spaces from the end of CaretLine. + while (CaretLine[CaretLine.size()-1] == ' ') + CaretLine.erase(CaretLine.end()-1); - // Copy the line of code into an std::string for ease of manipulation. - std::string SourceLine(LineStart, LineEnd); + // Emit what we have computed. + OS << SourceLine << '\n'; - // Create a line for the caret that is filled with spaces that is the same - // length as the line of source code. - std::string CaretLine(LineEnd-LineStart, ' '); + if (DiagOpts.ShowColors) + OS.changeColor(caretColor, true); + OS << CaretLine << '\n'; + if (DiagOpts.ShowColors) + OS.resetColor(); - // Highlight all of the characters covered by Ranges with ~ characters. - if (NumRanges) { - unsigned LineNo = SM.getLineNumber(FID, FileOffset); + if (!FixItInsertionLine.empty()) { + if (DiagOpts.ShowColors) + // Print fixit line in color + OS.changeColor(fixitColor, false); + if (DiagOpts.ShowSourceRanges) + OS << ' '; + OS << FixItInsertionLine << '\n'; + if (DiagOpts.ShowColors) + OS.resetColor(); + } - for (unsigned i = 0, e = NumRanges; i != e; ++i) - HighlightRange(Ranges[i], SM, LineNo, FID, CaretLine, SourceLine); + // Print out any parseable fixit information requested by the options. + EmitParseableFixits(Hints); } - // Next, insert the caret itself. - if (ColNo-1 < CaretLine.size()) - CaretLine[ColNo-1] = '^'; - else - CaretLine.push_back('^'); - - // Scan the source line, looking for tabs. If we find any, manually expand - // them to spaces and update the CaretLine to match. - for (unsigned i = 0; i != SourceLine.size(); ++i) { - if (SourceLine[i] != '\t') continue; - - // Replace this tab with at least one space. - SourceLine[i] = ' '; - - // Compute the number of spaces we need to insert. - unsigned TabStop = DiagOpts->TabStop; - assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && - "Invalid -ftabstop value"); - unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); - assert(NumSpaces < TabStop && "Invalid computation of space amt"); +private: + /// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo. + void HighlightRange(const CharSourceRange &R, + unsigned LineNo, FileID FID, + const std::string &SourceLine, + std::string &CaretLine) { + assert(CaretLine.size() == SourceLine.size() && + "Expect a correspondence between source and caret line!"); + if (!R.isValid()) return; + + SourceLocation Begin = SM.getExpansionLoc(R.getBegin()); + SourceLocation End = SM.getExpansionLoc(R.getEnd()); + + // If the End location and the start location are the same and are a macro + // location, then the range was something that came from a macro expansion + // or _Pragma. If this is an object-like macro, the best we can do is to + // highlight the range. If this is a function-like macro, we'd also like to + // highlight the arguments. + if (Begin == End && R.getEnd().isMacroID()) + End = SM.getExpansionRange(R.getEnd()).second; + + 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 #. + } - // Insert spaces into the SourceLine. - SourceLine.insert(i+1, NumSpaces, ' '); + // Compute the column number of the end. + unsigned EndColNo = CaretLine.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(); + } + } - // Insert spaces or ~'s into CaretLine. - CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' '); - } + 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 < SourceLine.size() && + (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) + ++StartColNo; + + // Pick the last non-whitespace column. + if (EndColNo > SourceLine.size()) + EndColNo = SourceLine.size(); + while (EndColNo-1 && + (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) + --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??"); + } - // If we are in -fdiagnostics-print-source-range-info mode, we are trying to - // produce easily machine parsable output. Add a space before the source line - // and the caret to make it trivial to tell the main diagnostic line from what - // the user is intended to see. - if (DiagOpts->ShowSourceRanges) { - SourceLine = ' ' + SourceLine; - CaretLine = ' ' + CaretLine; + // Fill the range with ~'s. + for (unsigned i = StartColNo; i < EndColNo; ++i) + CaretLine[i] = '~'; } - std::string FixItInsertionLine; - if (NumHints && DiagOpts->ShowFixits) { - for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints; - Hint != LastHint; ++Hint) { - if (!Hint->CodeToInsert.empty()) { + std::string BuildFixItInsertionLine(unsigned LineNo, + const char *LineStart, + const char *LineEnd, + ArrayRef<FixItHint> Hints) { + std::string FixItInsertionLine; + if (Hints.empty() || !DiagOpts.ShowFixits) + return FixItInsertionLine; + + 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 is on the same line as the caret. std::pair<FileID, unsigned> HintLocInfo - = SM.getDecomposedInstantiationLoc(Hint->RemoveRange.getBegin()); - if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) == - SM.getLineNumber(FID, FileOffset)) { + = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); + if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second)) { // Insert the new code into the line just below the code // that the user wrote. unsigned HintColNo = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second); unsigned LastColumnModified - = HintColNo - 1 + Hint->CodeToInsert.size(); + = HintColNo - 1 + I->CodeToInsert.size(); if (LastColumnModified > FixItInsertionLine.size()) FixItInsertionLine.resize(LastColumnModified, ' '); - std::copy(Hint->CodeToInsert.begin(), Hint->CodeToInsert.end(), + std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(), FixItInsertionLine.begin() + HintColNo - 1); } else { FixItInsertionLine.clear(); @@ -538,119 +652,348 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, } } } + + if (FixItInsertionLine.empty()) + return FixItInsertionLine; + // Now that we have the entire fixit line, expand the tabs in it. // Since we don't want to insert spaces in the middle of a word, // find each word and the column it should line up with and insert // spaces until they match. - if (!FixItInsertionLine.empty()) { - unsigned FixItPos = 0; - unsigned LinePos = 0; - unsigned TabExpandedCol = 0; - unsigned LineLength = LineEnd - LineStart; - - while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { - // Find the next word in the FixIt line. - while (FixItPos < FixItInsertionLine.size() && - FixItInsertionLine[FixItPos] == ' ') - ++FixItPos; - unsigned CharDistance = FixItPos - TabExpandedCol; - - // Walk forward in the source line, keeping track of - // the tab-expanded column. - for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) - if (LinePos >= LineLength || LineStart[LinePos] != '\t') - ++TabExpandedCol; - else - TabExpandedCol = - (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop; - - // Adjust the fixit line to match this column. - FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); - FixItPos = TabExpandedCol; - - // Walk to the end of the word. - while (FixItPos < FixItInsertionLine.size() && - FixItInsertionLine[FixItPos] != ' ') - ++FixItPos; - } + unsigned FixItPos = 0; + unsigned LinePos = 0; + unsigned TabExpandedCol = 0; + unsigned LineLength = LineEnd - LineStart; + + while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { + // Find the next word in the FixIt line. + while (FixItPos < FixItInsertionLine.size() && + FixItInsertionLine[FixItPos] == ' ') + ++FixItPos; + unsigned CharDistance = FixItPos - TabExpandedCol; + + // Walk forward in the source line, keeping track of + // the tab-expanded column. + for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) + if (LinePos >= LineLength || LineStart[LinePos] != '\t') + ++TabExpandedCol; + else + TabExpandedCol = + (TabExpandedCol/DiagOpts.TabStop + 1) * DiagOpts.TabStop; + + // Adjust the fixit line to match this column. + FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); + FixItPos = TabExpandedCol; + + // Walk to the end of the word. + while (FixItPos < FixItInsertionLine.size() && + FixItInsertionLine[FixItPos] != ' ') + ++FixItPos; } + + return FixItInsertionLine; } - // If the source line is too long for our terminal, select only the - // "interesting" source region within that line. - if (Columns && SourceLine.size() > Columns) - SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, - CaretEndColNo, Columns); + void ExpandTabs(std::string &SourceLine, std::string &CaretLine) { + // Scan the source line, looking for tabs. If we find any, manually expand + // them to spaces and update the CaretLine to match. + for (unsigned i = 0; i != SourceLine.size(); ++i) { + if (SourceLine[i] != '\t') continue; - // Finally, remove any blank spaces from the end of CaretLine. - while (CaretLine[CaretLine.size()-1] == ' ') - CaretLine.erase(CaretLine.end()-1); + // Replace this tab with at least one space. + SourceLine[i] = ' '; - // Emit what we have computed. - OS << SourceLine << '\n'; + // Compute the number of spaces we need to insert. + unsigned TabStop = DiagOpts.TabStop; + assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && + "Invalid -ftabstop value"); + unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); + assert(NumSpaces < TabStop && "Invalid computation of space amt"); - if (DiagOpts->ShowColors) - OS.changeColor(caretColor, true); - OS << CaretLine << '\n'; - if (DiagOpts->ShowColors) - OS.resetColor(); + // Insert spaces into the SourceLine. + SourceLine.insert(i+1, NumSpaces, ' '); - if (!FixItInsertionLine.empty()) { - if (DiagOpts->ShowColors) - // Print fixit line in color - OS.changeColor(fixitColor, false); - if (DiagOpts->ShowSourceRanges) - OS << ' '; - OS << FixItInsertionLine << '\n'; - if (DiagOpts->ShowColors) - OS.resetColor(); + // Insert spaces or ~'s into CaretLine. + CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' '); + } } - if (DiagOpts->ShowParseableFixits) { + void EmitParseableFixits(ArrayRef<FixItHint> Hints) { + if (!DiagOpts.ShowParseableFixits) + return; // We follow FixItRewriter's example in not (yet) handling // fix-its in macros. - bool BadApples = false; - for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) { - if (Hint->RemoveRange.isInvalid() || - Hint->RemoveRange.getBegin().isMacroID() || - Hint->RemoveRange.getEnd().isMacroID()) { - BadApples = true; + for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); + I != E; ++I) { + if (I->RemoveRange.isInvalid() || + I->RemoveRange.getBegin().isMacroID() || + I->RemoveRange.getEnd().isMacroID()) + return; + } + + for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); + I != E; ++I) { + SourceLocation BLoc = I->RemoveRange.getBegin(); + SourceLocation ELoc = I->RemoveRange.getEnd(); + + std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc); + std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc); + + // Adjust for token ranges. + if (I->RemoveRange.isTokenRange()) + EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts); + + // We specifically do not do word-wrapping or tab-expansion here, + // because this is supposed to be easy to parse. + PresumedLoc PLoc = SM.getPresumedLoc(BLoc); + if (PLoc.isInvalid()) break; + + OS << "fix-it:\""; + OS.write_escaped(PLoc.getFilename()); + OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second) + << ':' << SM.getColumnNumber(BInfo.first, BInfo.second) + << '-' << SM.getLineNumber(EInfo.first, EInfo.second) + << ':' << SM.getColumnNumber(EInfo.first, EInfo.second) + << "}:\""; + OS.write_escaped(I->CodeToInsert); + OS << "\"\n"; + } + } +}; + +} // end namespace + +/// Get the presumed location of a diagnostic message. This computes the +/// presumed location for the top of any macro backtrace when present. +static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM, + SourceLocation Loc) { + // This is a condensed form of the algorithm used by EmitCaretDiagnostic to + // walk to the top of the macro call stack. + while (Loc.isMacroID()) { + Loc = skipToMacroArgExpansion(SM, Loc); + Loc = getImmediateMacroCallerLoc(SM, Loc); + } + + return SM.getPresumedLoc(Loc); +} + +/// \brief Print out the file/line/column information and include trace. +/// +/// This method handlen the emission of the diagnostic location information. +/// This includes extracting as much location information as is present for the +/// diagnostic and printing it, as well as any include stack or source ranges +/// necessary. +void TextDiagnosticPrinter::EmitDiagnosticLoc(DiagnosticsEngine::Level Level, + const Diagnostic &Info, + const SourceManager &SM, + PresumedLoc PLoc) { + if (PLoc.isInvalid()) { + // At least print the file name if available: + FileID FID = SM.getFileID(Info.getLocation()); + if (!FID.isInvalid()) { + const FileEntry* FE = SM.getFileEntryForID(FID); + if (FE && FE->getName()) { + OS << FE->getName(); + if (FE->getDevice() == 0 && FE->getInode() == 0 + && FE->getFileMode() == 0) { + // in PCH is a guess, but a good one: + OS << " (in PCH)"; + } + OS << ": "; } } + return; + } + unsigned LineNo = PLoc.getLine(); + + if (!DiagOpts->ShowLocation) + return; + + if (DiagOpts->ShowColors) + OS.changeColor(savedColor, true); - if (!BadApples) { - for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) { + OS << PLoc.getFilename(); + switch (DiagOpts->Format) { + case DiagnosticOptions::Clang: OS << ':' << LineNo; break; + case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; + case DiagnosticOptions::Vi: OS << " +" << LineNo; break; + } - SourceLocation B = Hint->RemoveRange.getBegin(); - SourceLocation E = Hint->RemoveRange.getEnd(); + if (DiagOpts->ShowColumn) + // Compute the column number. + if (unsigned ColNo = PLoc.getColumn()) { + if (DiagOpts->Format == DiagnosticOptions::Msvc) { + OS << ','; + ColNo--; + } else + OS << ':'; + OS << ColNo; + } + switch (DiagOpts->Format) { + case DiagnosticOptions::Clang: + case DiagnosticOptions::Vi: OS << ':'; break; + case DiagnosticOptions::Msvc: OS << ") : "; break; + } - std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); - std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); + if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { + FileID CaretFileID = + SM.getFileID(SM.getExpansionLoc(Info.getLocation())); + bool PrintedRange = false; + + for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { + // Ignore invalid ranges. + if (!Info.getRange(i).isValid()) continue; + + SourceLocation B = Info.getRange(i).getBegin(); + SourceLocation E = Info.getRange(i).getEnd(); + B = SM.getExpansionLoc(B); + E = SM.getExpansionLoc(E); + + // If the End location and the start location are the same and are a + // macro location, then the range was something that came from a + // macro expansion or _Pragma. If this is an object-like macro, the + // best we can do is to highlight the range. If this is a + // function-like macro, we'd also like to highlight the arguments. + if (B == E && Info.getRange(i).getEnd().isMacroID()) + E = SM.getExpansionRange(Info.getRange(i).getEnd()).second; + + std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); + std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); + + // If the start or end of the range is in another file, just discard + // it. + if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) + continue; + + // Add in the length of the token, so that we cover multi-char + // tokens. + unsigned TokSize = 0; + if (Info.getRange(i).isTokenRange()) + TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); + + OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' + << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' + << SM.getLineNumber(EInfo.first, EInfo.second) << ':' + << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) + << '}'; + PrintedRange = true; + } + + if (PrintedRange) + OS << ':'; + } + OS << ' '; +} - // Adjust for token ranges. - if (Hint->RemoveRange.isTokenRange()) - EInfo.second += Lexer::MeasureTokenLength(E, SM, *LangOpts); +/// \brief Print the diagonstic level to a raw_ostream. +/// +/// Handles colorizing the level and formatting. +static void printDiagnosticLevel(raw_ostream &OS, + DiagnosticsEngine::Level Level, + bool ShowColors) { + if (ShowColors) { + // Print diagnostic category in bold and color + switch (Level) { + case DiagnosticsEngine::Ignored: + llvm_unreachable("Invalid diagnostic type"); + case DiagnosticsEngine::Note: OS.changeColor(noteColor, true); break; + case DiagnosticsEngine::Warning: OS.changeColor(warningColor, true); break; + case DiagnosticsEngine::Error: OS.changeColor(errorColor, true); break; + case DiagnosticsEngine::Fatal: OS.changeColor(fatalColor, true); break; + } + } - // We specifically do not do word-wrapping or tab-expansion here, - // because this is supposed to be easy to parse. - PresumedLoc PLoc = SM.getPresumedLoc(B); - if (PLoc.isInvalid()) - break; - - OS << "fix-it:\""; - OS.write_escaped(SM.getPresumedLoc(B).getFilename()); - OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second) - << ':' << SM.getColumnNumber(BInfo.first, BInfo.second) - << '-' << SM.getLineNumber(EInfo.first, EInfo.second) - << ':' << SM.getColumnNumber(EInfo.first, EInfo.second) - << "}:\""; - OS.write_escaped(Hint->CodeToInsert); - OS << "\"\n"; + switch (Level) { + case DiagnosticsEngine::Ignored: llvm_unreachable("Invalid diagnostic type"); + case DiagnosticsEngine::Note: OS << "note: "; break; + case DiagnosticsEngine::Warning: OS << "warning: "; break; + case DiagnosticsEngine::Error: OS << "error: "; break; + case DiagnosticsEngine::Fatal: OS << "fatal error: "; break; + } + + if (ShowColors) + OS.resetColor(); +} + +/// \brief Print the diagnostic name to a raw_ostream. +/// +/// This prints the diagnostic name to a raw_ostream if it has one. It formats +/// the name according to the expected diagnostic message formatting: +/// " [diagnostic_name_here]" +static void printDiagnosticName(raw_ostream &OS, const Diagnostic &Info) { + if (!DiagnosticIDs::isBuiltinNote(Info.getID())) + OS << " [" << DiagnosticIDs::getName(Info.getID()) << "]"; +} + +/// \brief Print any diagnostic option information to a raw_ostream. +/// +/// This implements all of the logic for adding diagnostic options to a message +/// (via OS). Each relevant option is comma separated and all are enclosed in +/// the standard bracketing: " [...]". +static void printDiagnosticOptions(raw_ostream &OS, + DiagnosticsEngine::Level Level, + const Diagnostic &Info, + const DiagnosticOptions &DiagOpts) { + bool Started = false; + if (DiagOpts.ShowOptionNames) { + // Handle special cases for non-warnings early. + if (Info.getID() == diag::fatal_too_many_errors) { + OS << " [-ferror-limit=]"; + return; + } + + // The code below is somewhat fragile because we are essentially trying to + // report to the user what happened by inferring what the diagnostic engine + // did. Eventually it might make more sense to have the diagnostic engine + // include some "why" information in the diagnostic. + + // If this is a warning which has been mapped to an error by the user (as + // inferred by checking whether the default mapping is to an error) then + // flag it as such. Note that diagnostics could also have been mapped by a + // pragma, but we don't currently have a way to distinguish this. + if (Level == DiagnosticsEngine::Error && + DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID()) && + !DiagnosticIDs::isDefaultMappingAsError(Info.getID())) { + OS << " [-Werror"; + Started = true; + } + + // If the diagnostic is an extension diagnostic and not enabled by default + // then it must have been turned on with -pedantic. + bool EnabledByDefault; + if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(), + EnabledByDefault) && + !EnabledByDefault) { + OS << (Started ? "," : " [") << "-pedantic"; + Started = true; + } + + StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID()); + if (!Opt.empty()) { + OS << (Started ? "," : " [") << "-W" << Opt; + Started = true; + } + } + + // If the user wants to see category information, include it too. + if (DiagOpts.ShowCategories) { + unsigned DiagCategory = + DiagnosticIDs::getCategoryNumberForDiag(Info.getID()); + if (DiagCategory) { + OS << (Started ? "," : " ["); + Started = true; + if (DiagOpts.ShowCategories == 1) + OS << DiagCategory; + else { + assert(DiagOpts.ShowCategories == 2 && "Invalid ShowCategories value"); + OS << DiagnosticIDs::getCategoryNameFromID(DiagCategory); } } } + if (Started) + OS << ']'; } /// \brief Skip over whitespace in the string, starting at the given @@ -659,9 +1002,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, /// \returns The index of the first non-whitespace character that is /// greater than or equal to Idx or, if no such character exists, /// returns the end of the string. -static unsigned skipWhitespace(unsigned Idx, - const llvm::SmallVectorImpl<char> &Str, - unsigned Length) { +static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) { while (Idx < Length && isspace(Str[Idx])) ++Idx; return Idx; @@ -692,8 +1033,7 @@ static inline char findMatchingPunctuation(char c) { /// /// \returns the index pointing one character past the end of the /// word. -static unsigned findEndOfWord(unsigned Start, - const llvm::SmallVectorImpl<char> &Str, +static unsigned findEndOfWord(unsigned Start, StringRef Str, unsigned Length, unsigned Column, unsigned Columns) { assert(Start < Str.size() && "Invalid start position!"); @@ -748,38 +1088,22 @@ static unsigned findEndOfWord(unsigned Start, /// \brief Print the given string to a stream, word-wrapping it to /// some number of columns in the process. /// -/// \brief OS the stream to which the word-wrapping string will be +/// \param OS the stream to which the word-wrapping string will be /// emitted. -/// -/// \brief Str the string to word-wrap and output. -/// -/// \brief Columns the number of columns to word-wrap to. -/// -/// \brief Column the column number at which the first character of \p +/// \param Str the string to word-wrap and output. +/// \param Columns the number of columns to word-wrap to. +/// \param Column the column number at which the first character of \p /// Str will be printed. This will be non-zero when part of the first /// line has already been printed. -/// -/// \brief Indentation the number of spaces to indent any lines beyond +/// \param Indentation the number of spaces to indent any lines beyond /// the first line. -/// /// \returns true if word-wrapping was required, or false if the /// string fit on the first line. -static bool PrintWordWrapped(llvm::raw_ostream &OS, - const llvm::SmallVectorImpl<char> &Str, +static bool printWordWrapped(raw_ostream &OS, StringRef Str, unsigned Columns, unsigned Column = 0, unsigned Indentation = WordWrapIndentation) { - unsigned Length = Str.size(); - - // If there is a newline in this message somewhere, find that - // newline and split the message into the part before the newline - // (which will be word-wrapped) and the part from the newline one - // (which will be emitted unchanged). - for (unsigned I = 0; I != Length; ++I) - if (Str[I] == '\n') { - Length = I; - break; - } + const unsigned Length = std::min(Str.find('\n'), Str.size()); // The string used to indent each line. llvm::SmallString<16> IndentStr; @@ -803,7 +1127,7 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS, OS << ' '; Column += 1; } - OS.write(&Str[WordStart], WordLength); + OS << Str.substr(WordStart, WordLength); Column += WordLength; continue; } @@ -812,38 +1136,57 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS, // line. OS << '\n'; OS.write(&IndentStr[0], Indentation); - OS.write(&Str[WordStart], WordLength); + OS << Str.substr(WordStart, WordLength); Column = Indentation + WordLength; Wrapped = true; } - if (Length == Str.size()) - return Wrapped; // We're done. + // Append any remaning text from the message with its existing formatting. + OS << Str.substr(Length); - // There is a newline in the message, followed by something that - // will not be word-wrapped. Print that. - OS.write(&Str[Length], Str.size() - Length); - return true; + return Wrapped; } -/// Get the presumed location of a diagnostic message. This computes the -/// presumed location for the top of any macro backtrace when present. -static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM, - SourceLocation Loc) { - // This is a condensed form of the algorithm used by EmitCaretDiagnostic to - // walk to the top of the macro call stack. - while (Loc.isMacroID()) { - Loc = skipToMacroArgExpansion(SM, Loc); - Loc = getImmediateMacroCallerLoc(SM, Loc); +static void printDiagnosticMessage(raw_ostream &OS, + DiagnosticsEngine::Level Level, + StringRef Message, + unsigned CurrentColumn, unsigned Columns, + bool ShowColors) { + if (ShowColors) { + // Print warnings, errors and fatal errors in bold, no color + switch (Level) { + case DiagnosticsEngine::Warning: OS.changeColor(savedColor, true); break; + case DiagnosticsEngine::Error: OS.changeColor(savedColor, true); break; + case DiagnosticsEngine::Fatal: OS.changeColor(savedColor, true); break; + default: break; //don't bold notes + } } - return SM.getPresumedLoc(Loc); + if (Columns) + printWordWrapped(OS, Message, Columns, CurrentColumn); + else + OS << Message; + + if (ShowColors) + OS.resetColor(); + OS << '\n'; } -void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) { +void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) { // Default implementation (Warnings/errors count). - DiagnosticClient::HandleDiagnostic(Level, Info); + DiagnosticConsumer::HandleDiagnostic(Level, Info); + + // Render the diagnostic message into a temporary buffer eagerly. We'll use + // this later as we print out the diagnostic to the terminal. + llvm::SmallString<100> OutStr; + Info.FormatDiagnostic(OutStr); + + llvm::raw_svector_ostream DiagMessageStream(OutStr); + if (DiagOpts->ShowNames) + printDiagnosticName(DiagMessageStream, Info); + printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts); + // Keeps track of the the starting position of the location // information (e.g., "foo.c:10:4:") that precedes the error @@ -854,289 +1197,82 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, if (!Prefix.empty()) OS << Prefix << ": "; - // If the location is specified, print out a file/line/col and include trace - // if enabled. - if (Info.getLocation().isValid()) { - const SourceManager &SM = Info.getSourceManager(); - PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Info.getLocation()); - if (PLoc.isInvalid()) { - // At least print the file name if available: - FileID FID = SM.getFileID(Info.getLocation()); - if (!FID.isInvalid()) { - const FileEntry* FE = SM.getFileEntryForID(FID); - if (FE && FE->getName()) { - OS << FE->getName(); - if (FE->getDevice() == 0 && FE->getInode() == 0 - && FE->getFileMode() == 0) { - // in PCH is a guess, but a good one: - OS << " (in PCH)"; - } - OS << ": "; - } - } - } else { - unsigned LineNo = PLoc.getLine(); - - // First, if this diagnostic is not in the main file, print out the - // "included from" lines. - if (LastWarningLoc != PLoc.getIncludeLoc()) { - LastWarningLoc = PLoc.getIncludeLoc(); - PrintIncludeStack(Level, LastWarningLoc, SM); - StartOfLocationInfo = OS.tell(); - } - - // Compute the column number. - if (DiagOpts->ShowLocation) { - if (DiagOpts->ShowColors) - OS.changeColor(savedColor, true); - - OS << PLoc.getFilename(); - switch (DiagOpts->Format) { - case DiagnosticOptions::Clang: OS << ':' << LineNo; break; - case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; - case DiagnosticOptions::Vi: OS << " +" << LineNo; break; - } - if (DiagOpts->ShowColumn) - if (unsigned ColNo = PLoc.getColumn()) { - if (DiagOpts->Format == DiagnosticOptions::Msvc) { - OS << ','; - ColNo--; - } else - OS << ':'; - OS << ColNo; - } - switch (DiagOpts->Format) { - case DiagnosticOptions::Clang: - case DiagnosticOptions::Vi: OS << ':'; break; - case DiagnosticOptions::Msvc: OS << ") : "; break; - } - - - if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { - FileID CaretFileID = - SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); - bool PrintedRange = false; - - for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { - // Ignore invalid ranges. - if (!Info.getRange(i).isValid()) continue; - - SourceLocation B = Info.getRange(i).getBegin(); - SourceLocation E = Info.getRange(i).getEnd(); - B = SM.getInstantiationLoc(B); - E = SM.getInstantiationLoc(E); - - // If the End location and the start location are the same and are a - // macro location, then the range was something that came from a - // macro expansion or _Pragma. If this is an object-like macro, the - // best we can do is to highlight the range. If this is a - // function-like macro, we'd also like to highlight the arguments. - if (B == E && Info.getRange(i).getEnd().isMacroID()) - E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second; - - std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); - std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); - - // If the start or end of the range is in another file, just discard - // it. - if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) - continue; - - // Add in the length of the token, so that we cover multi-char - // tokens. - unsigned TokSize = 0; - if (Info.getRange(i).isTokenRange()) - TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); - - OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' - << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' - << SM.getLineNumber(EInfo.first, EInfo.second) << ':' - << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) - << '}'; - PrintedRange = true; - } - - if (PrintedRange) - OS << ':'; - } - } - OS << ' '; - if (DiagOpts->ShowColors) - OS.resetColor(); - } - } - - if (DiagOpts->ShowColors) { - // Print diagnostic category in bold and color - switch (Level) { - case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); - case Diagnostic::Note: OS.changeColor(noteColor, true); break; - case Diagnostic::Warning: OS.changeColor(warningColor, true); break; - case Diagnostic::Error: OS.changeColor(errorColor, true); break; - case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break; - } - } - - switch (Level) { - case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); - case Diagnostic::Note: OS << "note: "; break; - case Diagnostic::Warning: OS << "warning: "; break; - case Diagnostic::Error: OS << "error: "; break; - case Diagnostic::Fatal: OS << "fatal error: "; break; + // Use a dedicated, simpler path for diagnostics without a valid location. + // This is important as if the location is missing, we may be emitting + // diagnostics in a context that lacks language options, a source manager, or + // other infrastructure necessary when emitting more rich diagnostics. + if (!Info.getLocation().isValid()) { + printDiagnosticLevel(OS, Level, DiagOpts->ShowColors); + printDiagnosticMessage(OS, Level, DiagMessageStream.str(), + OS.tell() - StartOfLocationInfo, + DiagOpts->MessageLength, DiagOpts->ShowColors); + OS.flush(); + return; } - if (DiagOpts->ShowColors) - OS.resetColor(); - - llvm::SmallString<100> OutStr; - Info.FormatDiagnostic(OutStr); + // Assert that the rest of our infrastructure is setup properly. + assert(LangOpts && "Unexpected diagnostic outside source file processing"); + assert(DiagOpts && "Unexpected diagnostic without options set"); + assert(Info.hasSourceManager() && + "Unexpected diagnostic with no source manager"); + const SourceManager &SM = Info.getSourceManager(); + TextDiagnostic TextDiag(*this, OS, SM, *LangOpts, *DiagOpts); - if (DiagOpts->ShowNames && - !DiagnosticIDs::isBuiltinNote(Info.getID())) { - OutStr += " ["; - OutStr += DiagnosticIDs::getName(Info.getID()); - OutStr += "]"; - } - - std::string OptionName; - if (DiagOpts->ShowOptionNames) { - // Was this a warning mapped to an error using -Werror or pragma? - if (Level == Diagnostic::Error && - DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID())) { - diag::Mapping mapping = diag::MAP_IGNORE; - Info.getDiags()->getDiagnosticLevel(Info.getID(), Info.getLocation(), - &mapping); - if (mapping == diag::MAP_WARNING) - OptionName += "-Werror"; - } + PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Info.getLocation()); - llvm::StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID()); - if (!Opt.empty()) { - if (!OptionName.empty()) - OptionName += ','; - OptionName += "-W"; - OptionName += Opt; - } else if (Info.getID() == diag::fatal_too_many_errors) { - OptionName = "-ferror-limit="; - } else { - // If the diagnostic is an extension diagnostic and not enabled by default - // then it must have been turned on with -pedantic. - bool EnabledByDefault; - if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(), - EnabledByDefault) && - !EnabledByDefault) - OptionName = "-pedantic"; - } - } - - // If the user wants to see category information, include it too. - unsigned DiagCategory = 0; - if (DiagOpts->ShowCategories) - DiagCategory = DiagnosticIDs::getCategoryNumberForDiag(Info.getID()); - - // If there is any categorization information, include it. - if (!OptionName.empty() || DiagCategory != 0) { - bool NeedsComma = false; - OutStr += " ["; - - if (!OptionName.empty()) { - OutStr += OptionName; - NeedsComma = true; - } - - if (DiagCategory) { - if (NeedsComma) OutStr += ','; - if (DiagOpts->ShowCategories == 1) - OutStr += llvm::utostr(DiagCategory); - else { - assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value"); - OutStr += DiagnosticIDs::getCategoryNameFromID(DiagCategory); - } - } - - OutStr += "]"; - } + // First, if this diagnostic is not in the main file, print out the + // "included from" lines. + PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM); + StartOfLocationInfo = OS.tell(); - - if (DiagOpts->ShowColors) { - // Print warnings, errors and fatal errors in bold, no color - switch (Level) { - case Diagnostic::Warning: OS.changeColor(savedColor, true); break; - case Diagnostic::Error: OS.changeColor(savedColor, true); break; - case Diagnostic::Fatal: OS.changeColor(savedColor, true); break; - default: break; //don't bold notes - } - } + // Next emit the location of this particular diagnostic. + EmitDiagnosticLoc(Level, Info, SM, PLoc); - if (DiagOpts->MessageLength) { - // We will be word-wrapping the error message, so compute the - // column number where we currently are (after printing the - // location information). - unsigned Column = OS.tell() - StartOfLocationInfo; - PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column); - } else { - OS.write(OutStr.begin(), OutStr.size()); - } - OS << '\n'; if (DiagOpts->ShowColors) OS.resetColor(); + printDiagnosticLevel(OS, Level, DiagOpts->ShowColors); + printDiagnosticMessage(OS, Level, DiagMessageStream.str(), + OS.tell() - StartOfLocationInfo, + DiagOpts->MessageLength, DiagOpts->ShowColors); + // If caret diagnostics are enabled and we have location, we want to // emit the caret. However, we only do this if the location moved // from the last diagnostic, if the last diagnostic was a note that // was part of a different warning or error diagnostic, or if the // diagnostic has ranges. We don't want to emit the same caret // multiple times if one loc has multiple diagnostics. - if (DiagOpts->ShowCarets && Info.getLocation().isValid() && + if (DiagOpts->ShowCarets && ((LastLoc != Info.getLocation()) || Info.getNumRanges() || - (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || + (LastCaretDiagnosticWasNote && Level != DiagnosticsEngine::Note) || Info.getNumFixItHints())) { // Cache the LastLoc, it allows us to omit duplicate source/caret spewage. LastLoc = FullSourceLoc(Info.getLocation(), Info.getSourceManager()); - LastCaretDiagnosticWasNote = (Level == Diagnostic::Note); + LastCaretDiagnosticWasNote = (Level == DiagnosticsEngine::Note); // Get the ranges into a local array we can hack on. - CharSourceRange Ranges[20]; - unsigned NumRanges = Info.getNumRanges(); - assert(NumRanges < 20 && "Out of space"); - for (unsigned i = 0; i != NumRanges; ++i) - Ranges[i] = Info.getRange(i); - - unsigned NumHints = Info.getNumFixItHints(); - for (unsigned i = 0; i != NumHints; ++i) { + SmallVector<CharSourceRange, 20> Ranges; + Ranges.reserve(Info.getNumRanges()); + for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) + Ranges.push_back(Info.getRange(i)); + + for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) { const FixItHint &Hint = Info.getFixItHint(i); - if (Hint.RemoveRange.isValid()) { - assert(NumRanges < 20 && "Out of space"); - Ranges[NumRanges++] = Hint.RemoveRange; - } + if (Hint.RemoveRange.isValid()) + Ranges.push_back(Hint.RemoveRange); } - const SourceManager &SM = LastLoc.getManager(); - unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0; - if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) { - // Compute the length of the macro-expansion backtrace, so that we - // can establish which steps in the macro backtrace we'll skip. - SourceLocation Loc = LastLoc; - unsigned Depth = 0; - do { - ++Depth; - Loc = skipToMacroArgExpansion(SM, Loc); - Loc = getImmediateMacroCallerLoc(SM, Loc); - } while (!Loc.isFileID()); - - if (Depth > DiagOpts->MacroBacktraceLimit) { - MacroInstSkipStart = DiagOpts->MacroBacktraceLimit / 2 + - DiagOpts->MacroBacktraceLimit % 2; - MacroInstSkipEnd = Depth - DiagOpts->MacroBacktraceLimit / 2; - } - } - - EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), - Info.getFixItHints(), - Info.getNumFixItHints(), - DiagOpts->MessageLength, - 0, MacroInstSkipStart, MacroInstSkipEnd); + unsigned MacroDepth = 0; + TextDiag.EmitCaret(LastLoc, Ranges, + llvm::makeArrayRef(Info.getFixItHints(), + Info.getNumFixItHints()), + MacroDepth); } OS.flush(); } + +DiagnosticConsumer * +TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { + return new TextDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index fff417e..cf35c8e 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -1,4 +1,4 @@ -//===--- VerifyDiagnosticsClient.cpp - Verifying Diagnostic Client --------===// +//===---- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ------===// // // The LLVM Compiler Infrastructure // @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/VerifyDiagnosticConsumer.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Lex/Preprocessor.h" @@ -20,19 +20,24 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; -VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags, - DiagnosticClient *_Primary) - : Diags(_Diags), PrimaryClient(_Primary), - Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) { +VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags) + : Diags(_Diags), PrimaryClient(Diags.getClient()), + OwnsPrimaryClient(Diags.ownsClient()), + Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) +{ + Diags.takeClient(); } -VerifyDiagnosticsClient::~VerifyDiagnosticsClient() { - CheckDiagnostics(); +VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() { + CheckDiagnostics(); + Diags.takeClient(); + if (OwnsPrimaryClient) + delete PrimaryClient; } -// DiagnosticClient interface. +// DiagnosticConsumer interface. -void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts, +void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP) { // FIXME: Const hack, we screw up the preprocessor but in practice its ok // because it doesn't get reused. It would be better if we could make a copy @@ -42,7 +47,7 @@ void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts, PrimaryClient->BeginSourceFile(LangOpts, PP); } -void VerifyDiagnosticsClient::EndSourceFile() { +void VerifyDiagnosticConsumer::EndSourceFile() { CheckDiagnostics(); PrimaryClient->EndSourceFile(); @@ -50,8 +55,12 @@ void VerifyDiagnosticsClient::EndSourceFile() { CurrentPreprocessor = 0; } -void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info) { +void VerifyDiagnosticConsumer::HandleDiagnostic( + DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { + if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) { + const SourceManager &SM = Info.getSourceManager(); + FirstErrorFID = SM.getFileID(Info.getLocation()); + } // Send the diagnostic to the buffer, we will check it once we reach the end // of the source file (or are destructed). Buffer->HandleDiagnostic(DiagLevel, Info); @@ -163,7 +172,7 @@ public: : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { } // Return true if string literal is next. - bool Next(llvm::StringRef S) { + bool Next(StringRef S) { P = C; PEnd = C + S.size(); if (PEnd > End) @@ -189,7 +198,7 @@ public: // Return true if string literal is found. // When true, P marks begin-position of S in content. - bool Search(llvm::StringRef S) { + bool Search(StringRef S) { P = std::search(C, End, S.begin(), S.end()); PEnd = P + S.size(); return P != End; @@ -278,7 +287,7 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, // next token: {{ if (!PH.Next("{{")) { - PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), + PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_start) << KindStr; continue; } @@ -287,7 +296,7 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, // search for token: }} if (!PH.Search("}}")) { - PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), + PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_end) << KindStr; continue; } @@ -296,11 +305,11 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, // build directive text; convert \n to newlines std::string Text; - llvm::StringRef NewlineStr = "\\n"; - llvm::StringRef Content(ContentBegin, ContentEnd-ContentBegin); + StringRef NewlineStr = "\\n"; + StringRef Content(ContentBegin, ContentEnd-ContentBegin); size_t CPos = 0; size_t FPos; - while ((FPos = Content.find(NewlineStr, CPos)) != llvm::StringRef::npos) { + while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) { Text += Content.substr(CPos, FPos-CPos); Text += '\n'; CPos = FPos + NewlineStr.size(); @@ -314,7 +323,7 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, if (D->isValid(Error)) DL->push_back(D); else { - PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin), + PP.Diag(Pos.getLocWithOffset(ContentBegin-PH.Begin), diag::err_verify_invalid_content) << KindStr << Error; } @@ -323,14 +332,12 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, /// FindExpectedDiags - Lex the main source file to find all of the // expected errors and warnings. -static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) { - // Create a raw lexer to pull all the comments out of the main file. We don't - // want to look in #include'd headers for expected-error strings. - SourceManager &SM = PP.getSourceManager(); - FileID FID = SM.getMainFileID(); - if (SM.getMainFileID().isInvalid()) +static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) { + // Create a raw lexer to pull all the comments out of FID. + if (FID.isInvalid()) return; + SourceManager& SM = PP.getSourceManager(); // Create a lexer to lex all the tokens of the main file in raw mode. const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); Lexer RawLex(FID, FromFile, SM, PP.getLangOptions()); @@ -357,7 +364,7 @@ static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) { /// happened. Print the map out in a nice format and return "true". If the map /// is empty and we're not going to print things, then return "false". /// -static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, +static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, const_diag_iterator diag_begin, const_diag_iterator diag_end, const char *Kind, bool Expected) { @@ -378,7 +385,7 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, return std::distance(diag_begin, diag_end); } -static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, +static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, DirectiveList &DL, const char *Kind, bool Expected) { if (DL.empty()) @@ -403,7 +410,7 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, /// CheckLists - Compare expected to seen diagnostic lists and return the /// the difference between them. /// -static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr, +static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const char *Label, DirectiveList &Left, const_diag_iterator d2_begin, @@ -446,7 +453,7 @@ static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr, /// were actually reported. It emits any discrepencies. Return "true" if there /// were problems. Return "false" otherwise. /// -static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr, +static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const TextDiagnosticBuffer &Buffer, ExpectedData &ED) { // We want to capture the delta between what was expected and what was @@ -471,21 +478,34 @@ static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr, return NumProblems; } -void VerifyDiagnosticsClient::CheckDiagnostics() { +void VerifyDiagnosticConsumer::CheckDiagnostics() { ExpectedData ED; // Ensure any diagnostics go to the primary client. - DiagnosticClient *CurClient = Diags.takeClient(); - Diags.setClient(PrimaryClient.get()); + bool OwnsCurClient = Diags.ownsClient(); + DiagnosticConsumer *CurClient = Diags.takeClient(); + Diags.setClient(PrimaryClient, false); // If we have a preprocessor, scan the source for expected diagnostic // markers. If not then any diagnostics are unexpected. if (CurrentPreprocessor) { - FindExpectedDiags(*CurrentPreprocessor, ED); + SourceManager &SM = CurrentPreprocessor->getSourceManager(); + // Extract expected-error strings from main file. + FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID()); + // Only check for expectations in other diagnostic locations + // if they are not the main file (via ID or FileEntry) - the main + // file has already been looked at, and its expectations must not + // be added twice. + if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID() + && (!SM.getFileEntryForID(FirstErrorFID) + || (SM.getFileEntryForID(FirstErrorFID) != + SM.getFileEntryForID(SM.getMainFileID())))) { + FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID); + FirstErrorFID = FileID(); + } // Check that the expected diagnostics occurred. - NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(), - *Buffer, ED); + NumErrors += CheckResults(Diags, SM, *Buffer, ED); } else { NumErrors += (PrintProblem(Diags, 0, Buffer->err_begin(), Buffer->err_end(), @@ -499,12 +519,20 @@ void VerifyDiagnosticsClient::CheckDiagnostics() { } Diags.takeClient(); - Diags.setClient(CurClient); + Diags.setClient(CurClient, OwnsCurClient); // Reset the buffer, we have processed all the diagnostics in it. Buffer.reset(new TextDiagnosticBuffer()); } +DiagnosticConsumer * +VerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const { + if (!Diags.getClient()) + Diags.setClient(PrimaryClient->clone(Diags)); + + return new VerifyDiagnosticConsumer(Diags); +} + Directive* Directive::Create(bool RegexKind, const SourceLocation &Location, const std::string &Text, unsigned Count) { if (RegexKind) diff --git a/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp index f12b484..8fbcd4b 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp @@ -31,12 +31,12 @@ #include <algorithm> using namespace clang; -void clang::ProcessWarningOptions(Diagnostic &Diags, +void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, const DiagnosticOptions &Opts) { Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); Diags.setShowOverloads( - static_cast<Diagnostic::OverloadsShown>(Opts.ShowOverloads)); + static_cast<DiagnosticsEngine::OverloadsShown>(Opts.ShowOverloads)); // Handle -ferror-limit if (Opts.ErrorLimit) @@ -48,14 +48,14 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, // extension diagnostics onto WARNING or ERROR unless the user has futz'd // around with them explicitly. if (Opts.PedanticErrors) - Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error); + Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Error); else if (Opts.Pedantic) - Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn); + Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Warn); else - Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore); + Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Ignore); for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { - llvm::StringRef Opt = Opts.Warnings[i]; + StringRef Opt = Opts.Warnings[i]; // Check to see if this warning starts with "no-", if so, this is a negative // form of the option. @@ -75,11 +75,18 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, Diags.setSuppressSystemWarnings(!isPositive); continue; } + + // -Weverything is a special case as well. It implicitly enables all + // warnings, including ones not explicitly in a warning group. + if (Opt == "everything") { + Diags.setEnableAllWarnings(true); + continue; + } // -Werror/-Wno-error is a special case, not controlled by the option table. // It also has the "specifier" form of -Werror=foo and -Werror-foo. if (Opt.startswith("error")) { - llvm::StringRef Specifier; + StringRef Specifier; if (Opt.size() > 5) { // Specifier must be present. if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) { Diags.Report(diag::warn_unknown_warning_specifier) @@ -94,14 +101,18 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, continue; } - // -Werror=foo maps foo to Error, -Wno-error=foo maps it to Warning. - Mapping = isPositive ? diag::MAP_ERROR : diag::MAP_WARNING_NO_WERROR; - Opt = Specifier; + // Set the warning as error flag for this specifier. + if (Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive)) { + Diags.Report(isPositive ? diag::warn_unknown_warning_option : + diag::warn_unknown_negative_warning_option) + << ("-W" + Opt.str()); + } + continue; } // -Wfatal-errors is yet another special case. if (Opt.startswith("fatal-errors")) { - llvm::StringRef Specifier; + StringRef Specifier; if (Opt.size() != 12) { if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) { Diags.Report(diag::warn_unknown_warning_specifier) @@ -116,15 +127,19 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, continue; } - // -Wfatal-errors=foo maps foo to Fatal, -Wno-fatal-errors=foo - // maps it to Error. - Mapping = isPositive ? diag::MAP_FATAL : diag::MAP_ERROR_NO_WFATAL; - Opt = Specifier; + // Set the error as fatal flag for this specifier. + if (Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive)) { + Diags.Report(isPositive ? diag::warn_unknown_warning_option : + diag::warn_unknown_negative_warning_option) + << ("-W" + Opt.str()); + } + continue; } - if (Diags.setDiagnosticGroupMapping(Opt, Mapping)) + if (Diags.setDiagnosticGroupMapping(Opt, Mapping)) { Diags.Report(isPositive ? diag::warn_unknown_warning_option : diag::warn_unknown_negative_warning_option) << ("-W" + Opt.str()); + } } } |