diff options
Diffstat (limited to 'lib/Frontend')
23 files changed, 1766 insertions, 823 deletions
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index eb7f270..92fb1e8 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -24,7 +24,7 @@ #include "llvm/Module.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -354,8 +354,18 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, PrintDeclContext(DC, Indentation+2); break; } + case Decl::IndirectField: { + IndirectFieldDecl* IFD = cast<IndirectFieldDecl>(*I); + Out << "<IndirectField> " << IFD << '\n'; + break; + } + case Decl::Label: { + LabelDecl *LD = cast<LabelDecl>(*I); + Out << "<Label> " << LD << '\n'; + break; + } case Decl::Field: { - FieldDecl* FD = cast<FieldDecl>(*I); + FieldDecl *FD = cast<FieldDecl>(*I); Out << "<field> " << FD << '\n'; break; } @@ -423,29 +433,21 @@ ASTConsumer *clang::CreateDeclContextPrinter() { } //===----------------------------------------------------------------------===// -/// InheritanceViewer - C++ Inheritance Visualization +/// ASTDumperXML - In-depth XML dumping. namespace { -class InheritanceViewer : public ASTConsumer { - const std::string clsname; +class ASTDumpXML : public ASTConsumer { + llvm::raw_ostream &OS; + public: - InheritanceViewer(const std::string& cname) : clsname(cname) {} + ASTDumpXML(llvm::raw_ostream &OS) : OS(OS) {} void HandleTranslationUnit(ASTContext &C) { - for (ASTContext::type_iterator I=C.types_begin(),E=C.types_end(); I!=E; ++I) - if (RecordType *T = dyn_cast<RecordType>(*I)) { - if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(T->getDecl())) { - // FIXME: This lookup needs to be generalized to handle namespaces and - // (when we support them) templates. - if (D->getNameAsString() == clsname) { - D->viewInheritance(C); - } - } - } - } + C.getTranslationUnitDecl()->dumpXML(OS); + } }; } -ASTConsumer *clang::CreateInheritanceViewer(const std::string& clsname) { - return new InheritanceViewer(clsname); +ASTConsumer *clang::CreateASTDumperXML(llvm::raw_ostream &OS) { + return new ASTDumpXML(OS); } diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp index b46212f..3905b99 100644 --- a/lib/Frontend/ASTMerge.cpp +++ b/lib/Frontend/ASTMerge.cpp @@ -38,23 +38,22 @@ void ASTMergeAction::ExecuteAction() { CI.getASTContext().getLangOptions()); CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &CI.getASTContext()); - llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics()); + llvm::IntrusiveRefCntPtr<DiagnosticIDs> + DiagIDs(CI.getDiagnostics().getDiagnosticIDs()); for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { - ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, false); + llvm::IntrusiveRefCntPtr<Diagnostic> + Diags(new Diagnostic(DiagIDs, CI.getDiagnostics().getClient(), + /*ShouldOwnClient=*/false)); + ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, + CI.getFileSystemOpts(), false); if (!Unit) continue; - // Reset the argument -> string function so that it has the AST - // context we want, since the Sema object created by - // LoadFromASTFile will override it. - CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument, - &CI.getASTContext()); - - ASTImporter Importer(CI.getDiagnostics(), - CI.getASTContext(), + ASTImporter Importer(CI.getASTContext(), CI.getFileManager(), Unit->getASTContext(), - Unit->getFileManager()); + Unit->getFileManager(), + /*MinimalImport=*/false); TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); for (DeclContext::decl_iterator D = TU->decls_begin(), diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index c76488b..4a5a51d 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -25,17 +25,21 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #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" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Support/Atomic.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/System/Host.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Timer.h" #include <cstdlib> @@ -43,20 +47,63 @@ #include <sys/stat.h> using namespace clang; +using llvm::TimeRecord; + +namespace { + class SimpleTimer { + bool WantTiming; + TimeRecord Start; + std::string Output; + + public: + explicit SimpleTimer(bool WantTiming) : WantTiming(WantTiming) { + if (WantTiming) + Start = TimeRecord::getCurrentTime(); + } + + void setOutput(const llvm::Twine &Output) { + if (WantTiming) + this->Output = Output.str(); + } + + ~SimpleTimer() { + if (WantTiming) { + TimeRecord Elapsed = TimeRecord::getCurrentTime(); + Elapsed -= Start; + llvm::errs() << Output << ':'; + Elapsed.print(Elapsed, llvm::errs()); + llvm::errs() << '\n'; + } + } + }; +} + /// \brief After failing to build a precompiled preamble (due to /// errors in the source that occurs in the preamble), the number of /// reparses during which we'll skip even trying to precompile the /// preamble. const unsigned DefaultPreambleRebuildInterval = 5; +/// \brief Tracks the number of ASTUnit objects that are currently active. +/// +/// Used for debugging purposes only. +static llvm::sys::cas_flag ActiveASTUnitObjects; + ASTUnit::ASTUnit(bool _MainFileIsAST) : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), - CompleteTranslationUnit(true), ConcurrencyCheckValue(CheckUnlocked), + CompleteTranslationUnit(true), WantTiming(getenv("LIBCLANG_TIMING")), + NumStoredDiagnosticsFromDriver(0), + ConcurrencyCheckValue(CheckUnlocked), PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0), ShouldCacheCodeCompletionResults(false), - NumTopLevelDeclsAtLastCompletionCache(0), - CacheCodeCompletionCoolDown(0), + CompletionCacheTopLevelHashValue(0), + PreambleTopLevelHashValue(0), + CurrentTopLevelHashValue(0), UnsafeToFree(false) { + if (getenv("LIBCLANG_OBJTRACKING")) { + llvm::sys::AtomicIncrement(&ActiveASTUnitObjects); + fprintf(stderr, "+++ %d translation units\n", ActiveASTUnitObjects); + } } ASTUnit::~ASTUnit() { @@ -82,10 +129,12 @@ ASTUnit::~ASTUnit() { delete SavedMainFileBuffer; delete PreambleBuffer; - ClearCachedCompletionResults(); + ClearCachedCompletionResults(); - for (unsigned I = 0, N = Timers.size(); I != N; ++I) - delete Timers[I]; + if (getenv("LIBCLANG_OBJTRACKING")) { + llvm::sys::AtomicDecrement(&ActiveASTUnitObjects); + fprintf(stderr, "--- %d translation units\n", ActiveASTUnitObjects); + } } void ASTUnit::CleanTemporaryFiles() { @@ -115,7 +164,8 @@ static unsigned getDeclShowContexts(NamedDecl *ND, | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) | (1 << (CodeCompletionContext::CCC_Statement - 1)) - | (1 << (CodeCompletionContext::CCC_Type - 1)); + | (1 << (CodeCompletionContext::CCC_Type - 1)) + | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1)); // In C++, types can appear in expressions contexts (for functional casts). if (LangOpts.CPlusPlus) @@ -141,12 +191,13 @@ static unsigned getDeclShowContexts(NamedDecl *ND, if (LangOpts.CPlusPlus) IsNestedNameSpecifier = true; - } else if (isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND)) + } else if (isa<ClassTemplateDecl>(ND)) IsNestedNameSpecifier = true; } else if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) { // Values can appear in these contexts. Contexts = (1 << (CodeCompletionContext::CCC_Statement - 1)) | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1)) | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)); } else if (isa<ObjCProtocolDecl>(ND)) { Contexts = (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1)); @@ -164,13 +215,8 @@ void ASTUnit::CacheCodeCompletionResults() { if (!TheSema) return; - llvm::Timer *CachingTimer = 0; - if (TimerGroup.get()) { - CachingTimer = new llvm::Timer("Cache global code completions", - *TimerGroup); - CachingTimer->startTimer(); - Timers.push_back(CachingTimer); - } + SimpleTimer Timer(WantTiming); + Timer.setOutput("Cache global code completions for " + getMainFileName()); // Clear out the previous results. ClearCachedCompletionResults(); @@ -178,7 +224,8 @@ void ASTUnit::CacheCodeCompletionResults() { // Gather the set of global code completions. typedef CodeCompletionResult Result; llvm::SmallVector<Result, 8> Results; - TheSema->GatherGlobalCodeCompletions(Results); + CachedCompletionAllocator = new GlobalCodeCompletionAllocator; + TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator, Results); // Translate global code completions into cached completions. llvm::DenseMap<CanQualType, unsigned> CompletionTypes; @@ -188,7 +235,8 @@ void ASTUnit::CacheCodeCompletionResults() { case Result::RK_Declaration: { bool IsNestedNameSpecifier = false; CachedCodeCompletionResult CachedResult; - CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema, + *CachedCompletionAllocator); CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration, Ctx->getLangOptions(), IsNestedNameSpecifier); @@ -237,7 +285,8 @@ void ASTUnit::CacheCodeCompletionResults() { | (1 << (CodeCompletionContext::CCC_UnionTag - 1)) | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)) | (1 << (CodeCompletionContext::CCC_Type - 1)) - | (1 << (CodeCompletionContext::CCC_PotentiallyQualifiedName - 1)); + | (1 << (CodeCompletionContext::CCC_PotentiallyQualifiedName - 1)) + | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1)); if (isa<NamespaceDecl>(Results[I].Declaration) || isa<NamespaceAliasDecl>(Results[I].Declaration)) @@ -249,7 +298,9 @@ void ASTUnit::CacheCodeCompletionResults() { // nested-name-specifier but isn't already an option, create a // nested-name-specifier completion. Results[I].StartsNestedNameSpecifier = true; - CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.Completion + = Results[I].CreateCodeCompletionString(*TheSema, + *CachedCompletionAllocator); CachedResult.ShowInContexts = RemainingContexts; CachedResult.Priority = CCP_NestedNameSpecifier; CachedResult.TypeClass = STC_Void; @@ -268,7 +319,9 @@ void ASTUnit::CacheCodeCompletionResults() { case Result::RK_Macro: { CachedCodeCompletionResult CachedResult; - CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.Completion + = Results[I].CreateCodeCompletionString(*TheSema, + *CachedCompletionAllocator); CachedResult.ShowInContexts = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1)) @@ -279,7 +332,9 @@ void ASTUnit::CacheCodeCompletionResults() { | (1 << (CodeCompletionContext::CCC_Expression - 1)) | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) | (1 << (CodeCompletionContext::CCC_MacroNameUse - 1)) - | (1 << (CodeCompletionContext::CCC_PreprocessorExpression - 1)); + | (1 << (CodeCompletionContext::CCC_PreprocessorExpression - 1)) + | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1)) + | (1 << (CodeCompletionContext::CCC_OtherWithMacros - 1)); CachedResult.Priority = Results[I].Priority; CachedResult.Kind = Results[I].CursorKind; @@ -290,22 +345,16 @@ void ASTUnit::CacheCodeCompletionResults() { break; } } - Results[I].Destroy(); } - - if (CachingTimer) - CachingTimer->stopTimer(); - // Make a note of the state when we performed this caching. - NumTopLevelDeclsAtLastCompletionCache = top_level_size(); - CacheCodeCompletionCoolDown = 15; + // Save the current top-level hash value. + CompletionCacheTopLevelHashValue = CurrentTopLevelHashValue; } void ASTUnit::ClearCachedCompletionResults() { - for (unsigned I = 0, N = CachedCompletionResults.size(); I != N; ++I) - delete CachedCompletionResults[I].Completion; CachedCompletionResults.clear(); CachedCompletionTypes.clear(); + CachedCompletionAllocator = 0; } namespace { @@ -378,7 +427,7 @@ class CaptureDroppedDiagnostics { public: CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags, - llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) + llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) : Diags(Diags), Client(StoredDiags), PreviousClient(0) { if (RequestCapture || Diags.getClient() == 0) { @@ -399,6 +448,9 @@ public: void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info) { + // Default implementation (Warnings/errors count). + DiagnosticClient::HandleDiagnostic(Level, Info); + StoredDiags.push_back(StoredDiagnostic(Level, Info)); } @@ -411,32 +463,48 @@ const std::string &ASTUnit::getASTFileName() { return static_cast<ASTReader *>(Ctx->getExternalSource())->getFileName(); } +llvm::MemoryBuffer *ASTUnit::getBufferForFile(llvm::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, + 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; + if (CaptureDiagnostics) + Client = new StoredDiagnosticClient(AST.StoredDiagnostics); + Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd- ArgBegin, + ArgBegin, Client); + } else if (CaptureDiagnostics) { + Diags->setClient(new StoredDiagnosticClient(AST.StoredDiagnostics)); + } +} + ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, llvm::IntrusiveRefCntPtr<Diagnostic> Diags, + const FileSystemOptions &FileSystemOpts, bool OnlyLocalDecls, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, bool CaptureDiagnostics) { llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); - - if (!Diags.getPtr()) { - // No diagnostics engine was provided, so create our own diagnostics object - // with the default options. - DiagnosticOptions DiagOpts; - Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); - } + ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics); - AST->CaptureDiagnostics = CaptureDiagnostics; AST->OnlyLocalDecls = OnlyLocalDecls; + AST->CaptureDiagnostics = CaptureDiagnostics; AST->Diagnostics = Diags; - AST->FileMgr.reset(new FileManager); - AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics())); + AST->FileMgr.reset(new FileManager(FileSystemOpts)); + AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics(), + AST->getFileManager())); AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); - // If requested, capture diagnostics in the ASTUnit. - CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(), - AST->StoredDiagnostics); - for (unsigned I = 0; I != NumRemappedFiles; ++I) { // Create the file entry for the file that we're mapping from. const FileEntry *FromFile @@ -471,7 +539,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple, Predefines, Counter)); - switch (Reader->ReadAST(Filename)) { + switch (Reader->ReadAST(Filename, ASTReader::MainFile)) { case ASTReader::Success: break; @@ -538,12 +606,69 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, namespace { +/// \brief Preprocessor callback class that updates a hash value with the names +/// of all macros that have been defined by the translation unit. +class MacroDefinitionTrackerPPCallbacks : public PPCallbacks { + unsigned &Hash; + +public: + explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { } + + virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { + Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash); + } +}; + +/// \brief Add the given declaration to the hash of all top-level entities. +void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) { + if (!D) + return; + + DeclContext *DC = D->getDeclContext(); + if (!DC) + return; + + if (!(DC->isTranslationUnit() || DC->getLookupParent()->isTranslationUnit())) + return; + + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { + if (ND->getIdentifier()) + Hash = llvm::HashString(ND->getIdentifier()->getName(), Hash); + else if (DeclarationName Name = ND->getDeclName()) { + std::string NameStr = Name.getAsString(); + Hash = llvm::HashString(NameStr, Hash); + } + return; + } + + if (ObjCForwardProtocolDecl *Forward + = dyn_cast<ObjCForwardProtocolDecl>(D)) { + for (ObjCForwardProtocolDecl::protocol_iterator + P = Forward->protocol_begin(), + PEnd = Forward->protocol_end(); + P != PEnd; ++P) + AddTopLevelDeclarationToHash(*P, 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); + return; + } +} + class TopLevelDeclTrackerConsumer : public ASTConsumer { ASTUnit &Unit; - + unsigned &Hash; + public: - TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {} - + TopLevelDeclTrackerConsumer(ASTUnit &_Unit, unsigned &Hash) + : Unit(_Unit), Hash(Hash) { + Hash = 0; + } + void HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) { Decl *D = *it; @@ -553,6 +678,8 @@ public: // fundamental problem in the parser right now. if (isa<ObjCMethodDecl>(D)) continue; + + AddTopLevelDeclarationToHash(D, Hash); Unit.addTopLevelDecl(D); } } @@ -567,7 +694,10 @@ public: virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return new TopLevelDeclTrackerConsumer(Unit); + CI.getPreprocessor().addPPCallbacks( + new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue())); + return new TopLevelDeclTrackerConsumer(Unit, + Unit.getCurrentTopLevelHashValue()); } public: @@ -579,15 +709,20 @@ public: } }; -class PrecompilePreambleConsumer : public PCHGenerator { +class PrecompilePreambleConsumer : public PCHGenerator, + public ASTSerializationListener { 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) { } + : PCHGenerator(PP, "", Chaining, isysroot, Out), Unit(Unit), + Hash(Unit.getCurrentTopLevelHashValue()) { + Hash = 0; + } virtual void HandleTopLevelDecl(DeclGroupRef D) { for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) { @@ -598,6 +733,7 @@ public: // fundamental problem in the parser right now. if (isa<ObjCMethodDecl>(D)) continue; + AddTopLevelDeclarationToHash(D, Hash); TopLevelDecls.push_back(D); } } @@ -614,6 +750,15 @@ 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 { @@ -625,14 +770,18 @@ public: virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { std::string Sysroot; + std::string OutputFile; llvm::raw_ostream *OS = 0; bool Chaining; - if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, + if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, + OutputFile, OS, Chaining)) return 0; const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? Sysroot.c_str() : 0; + CI.getPreprocessor().addPPCallbacks( + new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue())); return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Chaining, isysroot, OS); } @@ -666,11 +815,9 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // Set up diagnostics, capturing any diagnostics that would // otherwise be dropped. Clang.setDiagnostics(&getDiagnostics()); - CaptureDroppedDiagnostics Capture(CaptureDiagnostics, - getDiagnostics(), - StoredDiagnostics); // Create the target instance. + Clang.getTargetOpts().Features = TargetFeatures; Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), Clang.getTargetOpts())); if (!Clang.hasTarget()) { @@ -693,20 +840,25 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // Configure the various subsystems. // FIXME: Should we retain the previous file manager? - FileMgr.reset(new FileManager); - SourceMgr.reset(new SourceManager(getDiagnostics())); + FileSystemOpts = Clang.getFileSystemOpts(); + FileMgr.reset(new FileManager(Clang.getFileSystemOpts())); + SourceMgr.reset(new SourceManager(getDiagnostics(), *FileMgr)); TheSema.reset(); Ctx.reset(); PP.reset(); // Clear out old caches and data. TopLevelDecls.clear(); + PreprocessedEntities.clear(); CleanTemporaryFiles(); PreprocessedEntitiesByFile.clear(); if (!OverrideMainBuffer) { - StoredDiagnostics.clear(); + StoredDiagnostics.erase( + StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver, + StoredDiagnostics.end()); TopLevelDeclsInPreamble.clear(); + PreprocessedEntitiesInPreamble.clear(); } // Create a file manager object to provide access to and cache the filesystem. @@ -728,19 +880,21 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { PreprocessorOpts.ImplicitPCHInclude = PreambleFile; PreprocessorOpts.DisablePCHValidation = true; - // Keep track of the override buffer; - SavedMainFileBuffer = OverrideMainBuffer; - // The stored diagnostic has the old source manager in it; update // the locations to refer into the new source manager. Since we've // been careful to make sure that the source manager's state // before and after are identical, so that we can reuse the source // location itself. - for (unsigned I = 0, N = StoredDiagnostics.size(); I != N; ++I) { + for (unsigned I = NumStoredDiagnosticsFromDriver, + N = StoredDiagnostics.size(); + I < N; ++I) { FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), getSourceManager()); StoredDiagnostics[I].setLocation(Loc); } + + // Keep track of the override buffer; + SavedMainFileBuffer = OverrideMainBuffer; } else { PreprocessorOpts.PrecompiledPreambleBytes.first = 0; PreprocessorOpts.PrecompiledPreambleBytes.second = false; @@ -774,12 +928,6 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { } Invocation.reset(Clang.takeInvocation()); - - // If we were asked to cache code-completion results and don't have any - // results yet, do so now. - if (ShouldCacheCodeCompletionResults && CachedCompletionResults.empty()) - CacheCodeCompletionResults(); - return false; error: @@ -787,11 +935,12 @@ error: if (OverrideMainBuffer) { PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); - PreprocessorOpts.DisablePCHValidation = true; PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude; delete OverrideMainBuffer; + SavedMainFileBuffer = 0; } + StoredDiagnostics.clear(); Clang.takeSourceManager(); Clang.takeFileManager(); Invocation.reset(Clang.takeInvocation()); @@ -803,15 +952,27 @@ static std::string GetPreamblePCHPath() { // FIXME: This is lame; sys::Path should provide this function (in particular, // it should know how to find the temporary files dir). // FIXME: This is really lame. I copied this code from the Driver! + // FIXME: This is a hack so that we can override the preamble file during + // crash-recovery testing, which is the only case where the preamble files + // are not necessarily cleaned up. + const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"); + if (TmpFile) + return TmpFile; + std::string Error; const char *TmpDir = ::getenv("TMPDIR"); if (!TmpDir) TmpDir = ::getenv("TEMP"); if (!TmpDir) TmpDir = ::getenv("TMP"); +#ifdef LLVM_ON_WIN32 + if (!TmpDir) + TmpDir = ::getenv("USERPROFILE"); +#endif if (!TmpDir) TmpDir = "/tmp"; llvm::sys::Path P(TmpDir); + P.createDirectoryOnDisk(true); P.appendComponent("preamble"); P.appendSuffix("pch"); if (P.createTemporaryFileOnDisk()) @@ -827,8 +988,7 @@ std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines, bool &CreatedBuffer) { FrontendOptions &FrontendOpts = Invocation.getFrontendOpts(); - PreprocessorOptions &PreprocessorOpts - = Invocation.getPreprocessorOpts(); + PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts(); CreatedBuffer = false; // Try to determine if the main file has been remapped, either from the @@ -852,17 +1012,11 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, CreatedBuffer = false; } - Buffer = llvm::MemoryBuffer::getFile(M->second); + Buffer = getBufferForFile(M->second); if (!Buffer) return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true)); CreatedBuffer = true; - - // Remove this remapping. We've captured the buffer already. - M = PreprocessorOpts.eraseRemappedFile(M); - E = PreprocessorOpts.remapped_file_end(); - if (M == E) - break; } } } @@ -884,12 +1038,6 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, } Buffer = const_cast<llvm::MemoryBuffer *>(M->second); - - // Remove this remapping. We've captured the buffer already. - M = PreprocessorOpts.eraseRemappedFile(M); - E = PreprocessorOpts.remapped_file_buffer_end(); - if (M == E) - break; } } } @@ -897,7 +1045,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, // If the main source file was not remapped, load it now. if (!Buffer) { - Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second); + Buffer = getBufferForFile(FrontendOpts.Inputs[0].second); if (!Buffer) return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true)); @@ -908,7 +1056,6 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, } static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old, - bool DeleteOld, unsigned NewSize, llvm::StringRef NewName) { llvm::MemoryBuffer *Result @@ -919,9 +1066,6 @@ static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old, ' ', NewSize - Old->getBufferSize() - 1); const_cast<char*>(Result->getBufferEnd())[-1] = '\n'; - if (DeleteOld) - delete Old; - return Result; } @@ -957,6 +1101,11 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble = ComputePreamble(PreambleInvocation, MaxLines, CreatedPreambleBuffer); + // If ComputePreamble() Take ownership of the + llvm::OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer; + if (CreatedPreambleBuffer) + OwnedPreambleBuffer.reset(NewPreamble.first); + if (!NewPreamble.second.first) { // We couldn't find a preamble in the main source. Clear out the current // preamble, if we have one. It's obviously no good any more. @@ -965,8 +1114,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( llvm::sys::Path(PreambleFile).eraseFromDisk(); PreambleFile.clear(); } - if (CreatedPreambleBuffer) - delete NewPreamble.first; // The next time we actually see a preamble, precompile it. PreambleRebuildCounter = 1; @@ -1049,7 +1196,11 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Set the state of the diagnostic object to mimic its state // after parsing the preamble. + // FIXME: This won't catch any #pragma push warning changes that + // have occurred in the preamble. getDiagnostics().Reset(); + ProcessWarningOptions(getDiagnostics(), + PreambleInvocation.getDiagnosticOpts()); getDiagnostics().setNumWarnings(NumWarningsInPreamble); if (StoredDiagnostics.size() > NumStoredDiagnosticsInPreamble) StoredDiagnostics.erase( @@ -1059,7 +1210,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Create a version of the main file buffer that is padded to // buffer size we reserved when creating the preamble. return CreatePaddedMainFileBuffer(NewPreamble.first, - CreatedPreambleBuffer, PreambleReservedSize, FrontendOpts.Inputs[0].second); } @@ -1069,7 +1219,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // return now. if (!AllowRebuild) return 0; - + // We can't reuse the previously-computed preamble. Build a new one. Preamble.clear(); llvm::sys::Path(PreambleFile).eraseFromDisk(); @@ -1088,14 +1238,19 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( return 0; } - // We did not previously compute a preamble, or it can't be reused anyway. - llvm::Timer *PreambleTimer = 0; - if (TimerGroup.get()) { - PreambleTimer = new llvm::Timer("Precompiling preamble", *TimerGroup); - PreambleTimer->startTimer(); - Timers.push_back(PreambleTimer); + // Create a temporary file for the precompiled preamble. In rare + // circumstances, this can fail. + std::string PreamblePCHPath = GetPreamblePCHPath(); + if (PreamblePCHPath.empty()) { + // Try again next time. + PreambleRebuildCounter = 1; + return 0; } + // We did not previously compute a preamble, or it can't be reused anyway. + SimpleTimer PreambleTimer(WantTiming); + PreambleTimer.setOutput("Precompiling preamble"); + // Create a new buffer that stores the preamble. The buffer also contains // extra space for the original contents of the file (which will be present // when we actually parse the file) along with more room in case the file @@ -1129,11 +1284,11 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Tell the compiler invocation to generate a temporary precompiled header. FrontendOpts.ProgramAction = frontend::GeneratePCH; - // FIXME: Set ChainedPCH unconditionally, once it is ready. - if (::getenv("LIBCLANG_CHAINING")) - FrontendOpts.ChainedPCH = true; + FrontendOpts.ChainedPCH = true; // FIXME: Generate the precompiled header into memory? - FrontendOpts.OutputFile = GetPreamblePCHPath(); + FrontendOpts.OutputFile = PreamblePCHPath; + PreprocessorOpts.PrecompiledPreambleBytes.first = 0; + PreprocessorOpts.PrecompiledPreambleBytes.second = false; // Create the compiler instance to use for building the precompiled preamble. CompilerInstance Clang; @@ -1142,20 +1297,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Set up diagnostics, capturing all of the diagnostics produced. Clang.setDiagnostics(&getDiagnostics()); - CaptureDroppedDiagnostics Capture(CaptureDiagnostics, - getDiagnostics(), - StoredDiagnostics); // Create the target instance. + Clang.getTargetOpts().Features = TargetFeatures; Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), Clang.getTargetOpts())); if (!Clang.hasTarget()) { llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); - if (CreatedPreambleBuffer) - delete NewPreamble.first; - if (PreambleTimer) - PreambleTimer->stopTimer(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); @@ -1176,15 +1325,22 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( "IR inputs not support here!"); // Clear out old caches and data. - StoredDiagnostics.clear(); + getDiagnostics().Reset(); + ProcessWarningOptions(getDiagnostics(), Clang.getDiagnosticOpts()); + StoredDiagnostics.erase( + StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver, + 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.setFileManager(new FileManager(Clang.getFileSystemOpts())); // Create the source manager. - Clang.setSourceManager(new SourceManager(getDiagnostics())); + Clang.setSourceManager(new SourceManager(getDiagnostics(), + Clang.getFileManager())); llvm::OwningPtr<PrecompilePreambleAction> Act; Act.reset(new PrecompilePreambleAction(*this)); @@ -1193,10 +1349,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( Clang.takeInvocation(); llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); - if (CreatedPreambleBuffer) - delete NewPreamble.first; - if (PreambleTimer) - PreambleTimer->stopTimer(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); @@ -1213,11 +1365,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // FIXME: Should we leave a note for ourselves to try again? llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); - if (CreatedPreambleBuffer) - delete NewPreamble.first; - if (PreambleTimer) - PreambleTimer->stopTimer(); TopLevelDeclsInPreamble.clear(); + PreprocessedEntities.clear(); + PreprocessedEntitiesInPreamble.clear(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); @@ -1247,14 +1397,19 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( = std::make_pair(F->second->getSize(), File->getModificationTime()); } - if (PreambleTimer) - PreambleTimer->stopTimer(); - PreambleRebuildCounter = 1; PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); + + // If the hash of top-level entities differs from the hash of the top-level + // entities the last time we rebuilt the preamble, clear out the completion + // cache. + if (CurrentTopLevelHashValue != PreambleTopLevelHashValue) { + CompletionCacheTopLevelHashValue = 0; + PreambleTopLevelHashValue = CurrentTopLevelHashValue; + } + return CreatePaddedMainFileBuffer(NewPreamble.first, - CreatedPreambleBuffer, PreambleReservedSize, FrontendOpts.Inputs[0].second); } @@ -1274,14 +1429,90 @@ 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; - unsigned Result = 0; - if (isMainFileAST() || SavedMainFileBuffer) - ++Result; - return Result; + return 0; +} + +llvm::StringRef ASTUnit::getMainFileName() const { + return Invocation->getFrontendOpts().Inputs[0].second; +} + +bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { + if (!Invocation) + return true; + + // We'll manage file buffers ourselves. + Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true; + Invocation->getFrontendOpts().DisableFree = false; + ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); + + // Save the target features. + TargetFeatures = Invocation->getTargetOpts().Features; + + llvm::MemoryBuffer *OverrideMainBuffer = 0; + if (PrecompilePreamble) { + PreambleRebuildCounter = 2; + OverrideMainBuffer + = getMainBufferWithPrecompiledPreamble(*Invocation); + } + + SimpleTimer ParsingTimer(WantTiming); + ParsingTimer.setOutput("Parsing " + getMainFileName()); + + return Parse(OverrideMainBuffer); } ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, @@ -1290,50 +1521,19 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, bool CaptureDiagnostics, bool PrecompilePreamble, bool CompleteTranslationUnit, - bool CacheCodeCompletionResults) { - if (!Diags.getPtr()) { - // No diagnostics engine was provided, so create our own diagnostics object - // with the default options. - DiagnosticOptions DiagOpts; - Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); - } - + bool CacheCodeCompletionResults) { // Create the AST unit. llvm::OwningPtr<ASTUnit> AST; AST.reset(new ASTUnit(false)); + ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics); AST->Diagnostics = Diags; - AST->CaptureDiagnostics = CaptureDiagnostics; AST->OnlyLocalDecls = OnlyLocalDecls; + AST->CaptureDiagnostics = CaptureDiagnostics; AST->CompleteTranslationUnit = CompleteTranslationUnit; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->Invocation.reset(CI); - CI->getPreprocessorOpts().RetainRemappedFileBuffers = true; - - if (getenv("LIBCLANG_TIMING")) - AST->TimerGroup.reset( - new llvm::TimerGroup(CI->getFrontendOpts().Inputs[0].second)); - - llvm::MemoryBuffer *OverrideMainBuffer = 0; - // FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble. - if (PrecompilePreamble && !CI->getLangOpts().CPlusPlus) { - AST->PreambleRebuildCounter = 1; - OverrideMainBuffer - = AST->getMainBufferWithPrecompiledPreamble(*AST->Invocation); - } - - llvm::Timer *ParsingTimer = 0; - if (AST->TimerGroup.get()) { - ParsingTimer = new llvm::Timer("Initial parse", *AST->TimerGroup); - ParsingTimer->startTimer(); - AST->Timers.push_back(ParsingTimer); - } - - bool Failed = AST->Parse(OverrideMainBuffer); - if (ParsingTimer) - ParsingTimer->stopTimer(); - - return Failed? 0 : AST.take(); + return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take(); } ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, @@ -1341,20 +1541,20 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, llvm::IntrusiveRefCntPtr<Diagnostic> Diags, llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls, + bool CaptureDiagnostics, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, - bool CaptureDiagnostics, bool PrecompilePreamble, bool CompleteTranslationUnit, - bool CacheCodeCompletionResults) { - bool CreatedDiagnosticsObject = false; - + bool CacheCodeCompletionResults, + bool CXXPrecompilePreamble, + bool CXXChainedPCH) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. DiagnosticOptions DiagOpts; - Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); - CreatedDiagnosticsObject = true; + Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd - ArgBegin, + ArgBegin); } llvm::SmallVector<const char *, 16> Args; @@ -1365,40 +1565,49 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, // also want to force it to use clang. Args.push_back("-fsyntax-only"); - // FIXME: We shouldn't have to pass in the path info. - driver::Driver TheDriver("clang", llvm::sys::getHostTriple(), - "a.out", false, false, *Diags); - - // Don't check that inputs exist, they have been remapped. - TheDriver.setCheckInputsExist(false); - - llvm::OwningPtr<driver::Compilation> C( - TheDriver.BuildCompilation(Args.size(), Args.data())); + llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics; + + llvm::OwningPtr<CompilerInvocation> CI; - // We expect to get back exactly one command job, if we didn't something - // failed. - const driver::JobList &Jobs = C->getJobs(); - if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) { - llvm::SmallString<256> Msg; - llvm::raw_svector_ostream OS(Msg); - C->PrintJob(OS, C->getJobs(), "; ", true); - Diags->Report(diag::err_fe_expected_compiler_job) << OS.str(); - return 0; - } + { + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, + StoredDiagnostics); + + // FIXME: We shouldn't have to pass in the path info. + driver::Driver TheDriver("clang", llvm::sys::getHostTriple(), + "a.out", false, false, *Diags); + + // Don't check that inputs exist, they have been remapped. + TheDriver.setCheckInputsExist(false); + + llvm::OwningPtr<driver::Compilation> C( + TheDriver.BuildCompilation(Args.size(), Args.data())); + + // We expect to get back exactly one command job, if we didn't something + // failed. + const driver::JobList &Jobs = C->getJobs(); + if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) { + llvm::SmallString<256> Msg; + llvm::raw_svector_ostream OS(Msg); + C->PrintJob(OS, C->getJobs(), "; ", true); + Diags->Report(diag::err_fe_expected_compiler_job) << OS.str(); + return 0; + } - const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin()); - if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { - Diags->Report(diag::err_fe_expected_clang_command); - return 0; - } + const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin()); + if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { + Diags->Report(diag::err_fe_expected_clang_command); + return 0; + } - const driver::ArgStringList &CCArgs = Cmd->getArguments(); - llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation); - CompilerInvocation::CreateFromArgs(*CI, + const driver::ArgStringList &CCArgs = Cmd->getArguments(); + CI.reset(new CompilerInvocation); + CompilerInvocation::CreateFromArgs(*CI, const_cast<const char **>(CCArgs.data()), const_cast<const char **>(CCArgs.data()) + - CCArgs.size(), - *Diags); + CCArgs.size(), + *Diags); + } // Override any files that need remapping for (unsigned I = 0; I != NumRemappedFiles; ++I) @@ -1408,26 +1617,44 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, // Override the resources path. CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; - CI->getFrontendOpts().DisableFree = false; - return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls, - CaptureDiagnostics, PrecompilePreamble, - CompleteTranslationUnit, - CacheCodeCompletionResults); + // 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)); + ConfigureDiags(Diags, ArgBegin, ArgEnd, *AST, CaptureDiagnostics); + AST->Diagnostics = Diags; + + AST->FileMgr.reset(new FileManager(FileSystemOptions())); + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->CaptureDiagnostics = CaptureDiagnostics; + AST->CompleteTranslationUnit = CompleteTranslationUnit; + AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; + AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); + AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size(); + AST->StoredDiagnostics.swap(StoredDiagnostics); + AST->Invocation.reset(CI.take()); + return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0 : AST.take(); } bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { if (!Invocation.get()) return true; - llvm::Timer *ReparsingTimer = 0; - if (TimerGroup.get()) { - ReparsingTimer = new llvm::Timer("Reparse", *TimerGroup); - ReparsingTimer->startTimer(); - Timers.push_back(ReparsingTimer); - } - + SimpleTimer ParsingTimer(WantTiming); + ParsingTimer.setOutput("Reparsing " + getMainFileName()); + // Remap files. PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); + PPOpts.DisableStatCache = true; for (PreprocessorOptions::remapped_file_buffer_iterator R = PPOpts.remapped_file_buffer_begin(), REnd = PPOpts.remapped_file_buffer_end(); @@ -1447,21 +1674,20 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation); // Clear out the diagnostics state. - if (!OverrideMainBuffer) + if (!OverrideMainBuffer) { getDiagnostics().Reset(); + ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); + } // Parse the sources - bool Result = Parse(OverrideMainBuffer); - if (ReparsingTimer) - ReparsingTimer->stopTimer(); - - if (ShouldCacheCodeCompletionResults) { - if (CacheCodeCompletionCoolDown > 0) - --CacheCodeCompletionCoolDown; - else if (top_level_size() != NumTopLevelDeclsAtLastCompletionCache) - CacheCodeCompletionResults(); - } + bool Result = Parse(OverrideMainBuffer); + // If we're caching global code-completion results, and the top-level + // declarations have changed, clear out the code-completion cache. + if (!Result && ShouldCacheCodeCompletionResults && + CurrentTopLevelHashValue != CompletionCacheTopLevelHashValue) + CacheCodeCompletionResults(); + return Result; } @@ -1496,8 +1722,10 @@ namespace { | (1 << (CodeCompletionContext::CCC_Expression - 1)) | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) | (1 << (CodeCompletionContext::CCC_MemberAccess - 1)) - | (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1)); - + | (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1)) + | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1)) + | (1 << (CodeCompletionContext::CCC_Recovery - 1)); + if (AST.getASTContext().getLangOptions().CPlusPlus) NormalContexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1)) | (1 << (CodeCompletionContext::CCC_UnionTag - 1)) @@ -1514,19 +1742,23 @@ namespace { unsigned NumCandidates) { Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates); } + + virtual CodeCompletionAllocator &getAllocator() { + return Next.getAllocator(); + } }; } /// \brief Helper function that computes which global names are hidden by the /// local code-completion results. -void CalculateHiddenNames(const CodeCompletionContext &Context, - CodeCompletionResult *Results, - unsigned NumResults, - ASTContext &Ctx, - llvm::StringSet<> &HiddenNames) { +static void CalculateHiddenNames(const CodeCompletionContext &Context, + CodeCompletionResult *Results, + unsigned NumResults, + ASTContext &Ctx, + llvm::StringSet<llvm::BumpPtrAllocator> &HiddenNames){ bool OnlyTagNames = false; switch (Context.getKind()) { - case CodeCompletionContext::CCC_Other: + case CodeCompletionContext::CCC_Recovery: case CodeCompletionContext::CCC_TopLevel: case CodeCompletionContext::CCC_ObjCInterface: case CodeCompletionContext::CCC_ObjCImplementation: @@ -1540,6 +1772,7 @@ void CalculateHiddenNames(const CodeCompletionContext &Context, case CodeCompletionContext::CCC_Type: case CodeCompletionContext::CCC_Name: case CodeCompletionContext::CCC_PotentiallyQualifiedName: + case CodeCompletionContext::CCC_ParenthesizedExpression: break; case CodeCompletionContext::CCC_EnumTag: @@ -1556,6 +1789,8 @@ void CalculateHiddenNames(const CodeCompletionContext &Context, case CodeCompletionContext::CCC_NaturalLanguage: case CodeCompletionContext::CCC_SelectorName: case CodeCompletionContext::CCC_TypeQualifiers: + case CodeCompletionContext::CCC_Other: + case CodeCompletionContext::CCC_OtherWithMacros: // We're looking for nothing, or we're looking for names that cannot // be hidden. return; @@ -1600,12 +1835,11 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, // Merge the results we were given with the results we cached. bool AddedResult = false; unsigned InContexts - = (Context.getKind() == CodeCompletionContext::CCC_Other? NormalContexts + = (Context.getKind() == CodeCompletionContext::CCC_Recovery? NormalContexts : (1 << (Context.getKind() - 1))); // Contains the set of names that are hidden by "local" completion results. - llvm::StringSet<> HiddenNames; - llvm::SmallVector<CodeCompletionString *, 4> StringsToDestroy; + llvm::StringSet<llvm::BumpPtrAllocator> HiddenNames; typedef CodeCompletionResult Result; llvm::SmallVector<Result, 8> AllResults; for (ASTUnit::cached_completion_iterator @@ -1638,6 +1872,7 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, if (!Context.getPreferredType().isNull()) { if (C->Kind == CXCursor_MacroDefinition) { Priority = getMacroUsagePriority(C->Completion->getTypedText(), + S.getLangOptions(), Context.getPreferredType()->isAnyPointerType()); } else if (C->Type) { CanQualType Expected @@ -1663,11 +1898,12 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, Context.getKind() == CodeCompletionContext::CCC_MacroNameUse) { // Create a new code-completion string that just contains the // macro name, without its arguments. - Completion = new CodeCompletionString; - Completion->AddTypedTextChunk(C->Completion->getTypedText()); - StringsToDestroy.push_back(Completion); + CodeCompletionBuilder Builder(getAllocator(), CCP_CodePattern, + C->Availability); + Builder.AddTypedTextChunk(C->Completion->getTypedText()); CursorKind = CXCursor_NotImplemented; Priority = CCP_CodePattern; + Completion = Builder.TakeString(); } AllResults.push_back(Result(Completion, Priority, CursorKind, @@ -1683,9 +1919,6 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, Next.ProcessCodeCompleteResults(S, Context, AllResults.data(), AllResults.size()); - - for (unsigned I = 0, N = StringsToDestroy.size(); I != N; ++I) - delete StringsToDestroy[I]; } @@ -1703,16 +1936,9 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, if (!Invocation.get()) return; - llvm::Timer *CompletionTimer = 0; - if (TimerGroup.get()) { - llvm::SmallString<128> TimerName; - llvm::raw_svector_ostream TimerNameOut(TimerName); - TimerNameOut << "Code completion @ " << File << ":" << Line << ":" - << Column; - CompletionTimer = new llvm::Timer(TimerNameOut.str(), *TimerGroup); - CompletionTimer->startTimer(); - Timers.push_back(CompletionTimer); - } + SimpleTimer CompletionTimer(WantTiming); + CompletionTimer.setOutput("Code completion @ " + File + ":" + + llvm::Twine(Line) + ":" + llvm::Twine(Column)); CompilerInvocation CCInvocation(*Invocation); FrontendOptions &FrontendOpts = CCInvocation.getFrontendOpts(); @@ -1727,11 +1953,6 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, FrontendOpts.CodeCompletionAt.Line = Line; FrontendOpts.CodeCompletionAt.Column = Column; - // Turn on spell-checking when performing code completion. It leads - // to better results. - unsigned SpellChecking = CCInvocation.getLangOpts().SpellChecking; - CCInvocation.getLangOpts().SpellChecking = 1; - // Set the language options appropriately. LangOpts = CCInvocation.getLangOpts(); @@ -1741,16 +1962,17 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, // Set up diagnostics, capturing any diagnostics produced. Clang.setDiagnostics(&Diag); + ProcessWarningOptions(Diag, CCInvocation.getDiagnosticOpts()); CaptureDroppedDiagnostics Capture(true, - Clang.getDiagnostics(), + Clang.getDiagnostics(), StoredDiagnostics); // Create the target instance. + Clang.getTargetOpts().Features = TargetFeatures; Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), Clang.getTargetOpts())); if (!Clang.hasTarget()) { Clang.takeInvocation(); - CCInvocation.getLangOpts().SpellChecking = SpellChecking; return; } @@ -1783,11 +2005,12 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, // Use the code completion consumer we were given, but adding any cached // code-completion results. - AugmentedCodeCompleteConsumer - AugmentedConsumer(*this, Consumer, FrontendOpts.ShowMacrosInCodeCompletion, - FrontendOpts.ShowCodePatternsInCodeCompletion, - FrontendOpts.ShowGlobalSymbolsInCodeCompletion); - Clang.setCodeCompletionConsumer(&AugmentedConsumer); + AugmentedCodeCompleteConsumer *AugmentedConsumer + = new AugmentedCodeCompleteConsumer(*this, Consumer, + FrontendOpts.ShowMacrosInCodeCompletion, + FrontendOpts.ShowCodePatternsInCodeCompletion, + FrontendOpts.ShowGlobalSymbolsInCodeCompletion); + Clang.setCodeCompletionConsumer(AugmentedConsumer); // If we have a precompiled preamble, try to use it. We only allow // the use of the precompiled preamble if we're if the completion @@ -1808,6 +2031,10 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. + PreprocessorOpts.DisableStatCache = true; + StoredDiagnostics.insert(StoredDiagnostics.end(), + this->StoredDiagnostics.begin(), + this->StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver); if (OverrideMainBuffer) { PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); @@ -1819,12 +2046,14 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, // 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 = 0, N = this->StoredDiagnostics.size(); I != N; ++I) { + 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; @@ -1839,15 +2068,10 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, Act->EndSourceFile(); } - if (CompletionTimer) - CompletionTimer->stopTimer(); - // Steal back our resources. Clang.takeFileManager(); Clang.takeSourceManager(); Clang.takeInvocation(); - Clang.takeCodeCompletionConsumer(); - CCInvocation.getLangOpts().SpellChecking = SpellChecking; } bool ASTUnit::Save(llvm::StringRef File) { @@ -1865,7 +2089,7 @@ bool ASTUnit::Save(llvm::StringRef File) { std::vector<unsigned char> Buffer; llvm::BitstreamWriter Stream(Buffer); ASTWriter Writer(Stream); - Writer.WriteAST(getSema(), 0, 0); + Writer.WriteAST(getSema(), 0, std::string(), 0); // Write the generated bitstream to "Out". if (!Buffer.empty()) diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 5a31495..9f197b4 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -1,4 +1,12 @@ -set(LLVM_NO_RTTI 1) +set( LLVM_USED_LIBS + clangAST + clangBasic + clangDriver + clangLex + clangParse + clangSema + clangSerialization + ) add_clang_library(clangFrontend ASTConsumers.cpp @@ -15,9 +23,11 @@ add_clang_library(clangFrontend FrontendAction.cpp FrontendActions.cpp FrontendOptions.cpp + HeaderIncludeGen.cpp InitHeaderSearch.cpp InitPreprocessor.cpp LangStandards.cpp + MultiplexConsumer.cpp PrintPreprocessedOutput.cpp StmtXML.cpp TextDiagnosticBuffer.cpp @@ -38,6 +48,7 @@ ENDIF(MSVC) add_dependencies(clangFrontend ClangAttrClasses ClangAttrList + ClangCC1Options ClangDiagnosticFrontend ClangDiagnosticLex ClangDiagnosticSema diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index 53f7362..ee3fdd8 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -13,18 +13,20 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/Utils.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/Diagnostic.h" #include "clang/Basic/OnDiskHashTable.h" +#include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" // FIXME: put this somewhere else? #ifndef S_ISDIR @@ -189,8 +191,6 @@ class PTHWriter { void Emit16(uint32_t V) { ::Emit16(Out, V); } - void Emit24(uint32_t V) { ::Emit24(Out, V); } - void Emit32(uint32_t V) { ::Emit32(Out, V); } void EmitBuf(const char *Ptr, unsigned NumBytes) { @@ -300,7 +300,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { ParsingPreprocessorDirective = false; } - if (Tok.is(tok::identifier)) { + if (Tok.is(tok::raw_identifier)) { PP.LookUpIdentifierInfo(Tok); EmitToken(Tok); continue; @@ -320,13 +320,13 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { // this case, discard both tokens. if (NextTok.isAtStartOfLine()) goto NextToken; - + // The token is the start of a directive. Emit it. EmitToken(Tok); Tok = NextTok; // Did we see 'include'/'import'/'include_next'? - if (Tok.isNot(tok::identifier)) { + if (Tok.isNot(tok::raw_identifier)) { EmitToken(Tok); continue; } @@ -353,7 +353,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { L.LexIncludeFilename(Tok); L.setParsingPreprocessorDirective(false); assert(!Tok.isAtStartOfLine()); - if (Tok.is(tok::identifier)) + if (Tok.is(tok::raw_identifier)) PP.LookUpIdentifierInfo(Tok); break; @@ -476,8 +476,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) { const FileEntry *FE = C.Entry; // FIXME: Handle files with non-absolute paths. - llvm::sys::Path P(FE->getName()); - if (!P.isAbsolute()) + if (llvm::sys::path::is_relative(FE->getName())) continue; const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics(), SM); @@ -512,26 +511,27 @@ namespace { /// as input to PTH generation. StatListener populates the PTHWriter's /// file map with stat information for directories as well as negative stats. /// Stat information for files are populated elsewhere. -class StatListener : public StatSysCallCache { +class StatListener : public FileSystemStatCache { PTHMap &PM; public: StatListener(PTHMap &pm) : PM(pm) {} ~StatListener() {} - int stat(const char *path, struct stat *buf) { - int result = StatSysCallCache::stat(path, buf); + LookupResult getStat(const char *Path, struct stat &StatBuf, + int *FileDescriptor) { + LookupResult Result = statChained(Path, StatBuf, FileDescriptor); - if (result != 0) // Failed 'stat'. - PM.insert(PTHEntryKeyVariant(path), PTHEntry()); - else if (S_ISDIR(buf->st_mode)) { + if (Result == CacheMissing) // Failed 'stat'. + PM.insert(PTHEntryKeyVariant(Path), PTHEntry()); + else if (S_ISDIR(StatBuf.st_mode)) { // Only cache directories with absolute paths. - if (!llvm::sys::Path(path).isAbsolute()) - return result; + if (llvm::sys::path::is_relative(Path)) + return Result; - PM.insert(PTHEntryKeyVariant(buf, path), PTHEntry()); + PM.insert(PTHEntryKeyVariant(&StatBuf, Path), PTHEntry()); } - return result; + return Result; } }; } // end anonymous namespace @@ -541,9 +541,9 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { // Get the name of the main file. const SourceManager &SrcMgr = PP.getSourceManager(); const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID()); - llvm::sys::Path MainFilePath(MainFile->getName()); + llvm::SmallString<128> MainFilePath(MainFile->getName()); - MainFilePath.makeAbsolute(); + llvm::sys::fs::make_absolute(MainFilePath); // Create the PTHWriter. PTHWriter PW(*OS, PP); diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index ce0b072..fd593de 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -27,14 +27,16 @@ #include "clang/Frontend/Utils.h" #include "clang/Serialization/ASTReader.h" #include "clang/Sema/CodeCompleteConsumer.h" -#include "llvm/LLVMContext.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Timer.h" -#include "llvm/System/Host.h" -#include "llvm/System/Path.h" -#include "llvm/System/Program.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" using namespace clang; CompilerInstance::CompilerInstance() @@ -44,10 +46,6 @@ CompilerInstance::CompilerInstance() CompilerInstance::~CompilerInstance() { } -void CompilerInstance::setLLVMContext(llvm::LLVMContext *Value) { - LLVMContext.reset(Value); -} - void CompilerInstance::setInvocation(CompilerInvocation *Value) { Invocation.reset(Value); } @@ -89,26 +87,8 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { } // Diagnostics -namespace { - class BinaryDiagnosticSerializer : public DiagnosticClient { - llvm::raw_ostream &OS; - SourceManager *SourceMgr; - public: - explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS) - : OS(OS), SourceMgr(0) { } - - virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info); - }; -} - -void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info) { - StoredDiagnostic(DiagLevel, Info).Serialize(OS); -} - static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, - unsigned argc, char **argv, + unsigned argc, const char* const *argv, Diagnostic &Diags) { std::string ErrorInfo; llvm::OwningPtr<llvm::raw_ostream> OS( @@ -130,33 +110,24 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger)); } -void CompilerInstance::createDiagnostics(int Argc, char **Argv) { - Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv); +void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv, + DiagnosticClient *Client) { + Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client); } llvm::IntrusiveRefCntPtr<Diagnostic> CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, - int Argc, char **Argv) { - llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic()); + int Argc, const char* const *Argv, + DiagnosticClient *Client) { + llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID)); // Create the diagnostic client for reporting errors or for // implementing -verify. - llvm::OwningPtr<DiagnosticClient> DiagClient; - if (Opts.BinaryOutput) { - if (llvm::sys::Program::ChangeStderrToBinary()) { - // We weren't able to set standard error to binary, which is a - // bit of a problem. So, just create a text diagnostic printer - // to complain about this problem, and pretend that the user - // didn't try to use binary output. - Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); - Diags->Report(diag::err_fe_stderr_binary); - return Diags; - } else { - Diags->setClient(new BinaryDiagnosticSerializer(llvm::errs())); - } - } else { + if (Client) + Diags->setClient(Client); + else Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); - } // Chain in -verify checker, if requested. if (Opts.VerifyDiagnostics) @@ -174,13 +145,13 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, // File Manager void CompilerInstance::createFileManager() { - FileMgr.reset(new FileManager()); + FileMgr.reset(new FileManager(getFileSystemOpts())); } // Source Manager -void CompilerInstance::createSourceManager() { - SourceMgr.reset(new SourceManager(getDiagnostics())); +void CompilerInstance::createSourceManager(FileManager &FileMgr) { + SourceMgr.reset(new SourceManager(getDiagnostics(), FileMgr)); } // Preprocessor @@ -231,6 +202,16 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, if (!DepOpts.OutputFile.empty()) AttachDependencyFileGen(*PP, DepOpts); + // Handle generating header include information, if requested. + if (DepOpts.ShowHeaderIncludes) + AttachHeaderIncludeGen(*PP); + if (!DepOpts.HeaderIncludeOutputFile.empty()) { + llvm::StringRef OutputPath = DepOpts.HeaderIncludeOutputFile; + if (OutputPath == "-") + OutputPath = ""; + AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath); + } + return PP; } @@ -248,12 +229,16 @@ void CompilerInstance::createASTContext() { void CompilerInstance::createPCHExternalASTSource(llvm::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)); + DeserializationListener, + Preamble)); getASTContext().setExternalSource(Source); } @@ -261,17 +246,20 @@ ExternalASTSource * CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, + bool DisableStatCache, Preprocessor &PP, ASTContext &Context, - void *DeserializationListener) { + void *DeserializationListener, + bool Preamble) { llvm::OwningPtr<ASTReader> Reader; Reader.reset(new ASTReader(PP, &Context, Sysroot.empty() ? 0 : Sysroot.c_str(), - DisablePCHValidation)); + DisablePCHValidation, DisableStatCache)); Reader->setDeserializationListener( static_cast<ASTDeserializationListener *>(DeserializationListener)); - switch (Reader->ReadAST(Path)) { + switch (Reader->ReadAST(Path, + Preamble ? ASTReader::Preamble : ASTReader::PCH)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. @@ -316,7 +304,6 @@ void CompilerInstance::createCodeCompletionConsumer() { CompletionConsumer.reset( createCodeCompletionConsumer(getPreprocessor(), Loc.FileName, Loc.Line, Loc.Column, - getFrontendOpts().DebugCodeCompletionPrinter, getFrontendOpts().ShowMacrosInCodeCompletion, getFrontendOpts().ShowCodePatternsInCodeCompletion, getFrontendOpts().ShowGlobalSymbolsInCodeCompletion, @@ -345,7 +332,6 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename, unsigned Line, unsigned Column, - bool UseDebugPrinter, bool ShowMacros, bool ShowCodePatterns, bool ShowGlobals, @@ -354,11 +340,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, return 0; // Set up the creation routine for code-completion. - if (UseDebugPrinter) - return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, - ShowGlobals, OS); - else - return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, + return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, ShowGlobals, OS); } @@ -370,18 +352,34 @@ void CompilerInstance::createSema(bool CompleteTranslationUnit, // Output Files -void CompilerInstance::addOutputFile(llvm::StringRef Path, - llvm::raw_ostream *OS) { - assert(OS && "Attempt to add empty stream to output list!"); - OutputFiles.push_back(std::make_pair(Path, OS)); +void CompilerInstance::addOutputFile(const OutputFile &OutFile) { + assert(OutFile.OS && "Attempt to add empty stream to output list!"); + OutputFiles.push_back(OutFile); } void CompilerInstance::clearOutputFiles(bool EraseFiles) { - for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator + for (std::list<OutputFile>::iterator it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { - delete it->second; - if (EraseFiles && !it->first.empty()) - llvm::sys::Path(it->first).eraseFromDisk(); + delete it->OS; + if (!it->TempFilename.empty()) { + llvm::sys::Path TempPath(it->TempFilename); + if (EraseFiles) + TempPath.eraseFromDisk(); + else { + std::string Error; + llvm::sys::Path NewOutFile(it->Filename); + // If '-working-directory' was passed, the output filename should be + // relative to that. + FileManager::FixupRelativePath(NewOutFile, getFileSystemOpts()); + if (TempPath.renamePathOnDisk(NewOutFile, &Error)) { + getDiagnostics().Report(diag::err_fe_unable_to_rename_temp) + << it->TempFilename << it->Filename << Error; + TempPath.eraseFromDisk(); + } + } + } else if (!it->Filename.empty() && EraseFiles) + llvm::sys::Path(it->Filename).eraseFromDisk(); + } OutputFiles.clear(); } @@ -391,18 +389,20 @@ CompilerInstance::createDefaultOutputFile(bool Binary, llvm::StringRef InFile, llvm::StringRef Extension) { return createOutputFile(getFrontendOpts().OutputFile, Binary, - InFile, Extension); + /*RemoveFileOnSignal=*/true, InFile, Extension); } llvm::raw_fd_ostream * CompilerInstance::createOutputFile(llvm::StringRef OutputPath, - bool Binary, + bool Binary, bool RemoveFileOnSignal, llvm::StringRef InFile, llvm::StringRef Extension) { - std::string Error, OutputPathName; + std::string Error, OutputPathName, TempPathName; llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, + RemoveFileOnSignal, InFile, Extension, - &OutputPathName); + &OutputPathName, + &TempPathName); if (!OS) { getDiagnostics().Report(diag::err_fe_unable_to_open_output) << OutputPath << Error; @@ -411,7 +411,8 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, // Add the output file -- but don't try to remove "-", since this means we are // using stdin. - addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS); + addOutputFile(OutputFile((OutputPathName != "-") ? OutputPathName : "", + TempPathName, OS)); return OS; } @@ -420,10 +421,12 @@ llvm::raw_fd_ostream * CompilerInstance::createOutputFile(llvm::StringRef OutputPath, std::string &Error, bool Binary, + bool RemoveFileOnSignal, llvm::StringRef InFile, llvm::StringRef Extension, - std::string *ResultPathName) { - std::string OutFile; + std::string *ResultPathName, + std::string *TempPathName) { + std::string OutFile, TempFile; if (!OutputPath.empty()) { OutFile = OutputPath; } else if (InFile == "-") { @@ -436,15 +439,39 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, } else { OutFile = "-"; } + + if (OutFile != "-") { + llvm::sys::Path OutPath(OutFile); + // Only create the temporary if we can actually write to OutPath, otherwise + // we want to fail early. + bool Exists; + 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(); + } + } + + std::string OSFile = OutFile; + if (!TempFile.empty()) + OSFile = TempFile; llvm::OwningPtr<llvm::raw_fd_ostream> OS( - new llvm::raw_fd_ostream(OutFile.c_str(), Error, + 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) + llvm::sys::RemoveFileOnSignal(llvm::sys::Path(OSFile)); + if (ResultPathName) *ResultPathName = OutFile; + if (TempPathName) + *TempPathName = TempFile; return OS.take(); } @@ -461,23 +488,32 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { - // Figure out where to get and map in the main file. - if (InputFile != "-") { + // 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 != "-") { const FileEntry *File = FileMgr.getFile(InputFile); - if (File) SourceMgr.createMainFileID(File); - if (SourceMgr.getMainFileID().isInvalid()) { + if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; } + SourceMgr.createMainFileID(File); } else { - llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN(); - if (SB) SourceMgr.createMainFileIDForMemBuffer(SB); - if (SourceMgr.getMainFileID().isInvalid()) { + llvm::OwningPtr<llvm::MemoryBuffer> SB; + if (llvm::MemoryBuffer::getSTDIN(SB)) { + // FIXME: Give ec.message() in this diag. Diags.Report(diag::err_fe_error_reading_stdin); return false; } + const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(), + SB->getBufferSize(), 0); + SourceMgr.createMainFileID(File); + SourceMgr.overrideFileContents(File, SB.take()); } + assert(!SourceMgr.getMainFileID().isInvalid() && + "Couldn't establish MainFileID!"); return true; } @@ -529,9 +565,10 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { } if (getDiagnosticOpts().ShowCarets) { - unsigned NumWarnings = getDiagnostics().getNumWarnings(); - unsigned NumErrors = getDiagnostics().getNumErrors() - - getDiagnostics().getNumErrorsSuppressed(); + // We can have multiple diagnostics sharing one diagnostic client. + // 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"); @@ -548,15 +585,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { OS << "\n"; } - // Return the appropriate status when verifying diagnostics. - // - // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need - // this. - if (getDiagnosticOpts().VerifyDiagnostics) - return !static_cast<VerifyDiagnosticsClient&>( - getDiagnosticClient()).HadErrors(); - - return !getDiagnostics().getNumErrors(); + return !getDiagnostics().getClient()->getNumErrors(); } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 8c64483..103d251 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -10,6 +10,7 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/Version.h" +#include "clang/Basic/FileManager.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/CC1Options.h" @@ -25,8 +26,8 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/System/Host.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" using namespace clang; static const char *getAnalysisName(Analyses Kind) { @@ -99,6 +100,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-display-progress"); if (Opts.AnalyzeNestedBlocks) Res.push_back("-analyzer-opt-analyze-nested-blocks"); + if (Opts.AnalyzerStats) + Res.push_back("-analyzer-stats"); if (Opts.EagerlyAssume) Res.push_back("-analyzer-eagerly-assume"); if (!Opts.PurgeDead) @@ -113,8 +116,17 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-experimental-checks"); if (Opts.EnableExperimentalInternalChecks) Res.push_back("-analyzer-experimental-internal-checks"); - if (Opts.IdempotentOps) - Res.push_back("-analyzer-check-idempotent-operations"); + if (Opts.BufferOverflows) + Res.push_back("-analyzer-check-buffer-overflows"); + + for (unsigned i = 0, e = Opts.CheckersControlList.size(); i != e; ++i) { + const std::pair<std::string, bool> &opt = Opts.CheckersControlList[i]; + if (opt.second) + Res.push_back("-analyzer-disable-checker"); + else + Res.push_back("-analyzer-checker"); + Res.push_back(opt.first); + } } static void CodeGenOptsToArgs(const CodeGenOptions &Opts, @@ -150,7 +162,7 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, // TimePasses is only derived. // UnitAtATime is unused. // Inlining is only derived. - + // UnrollLoops is derived, but also accepts an option, no // harm in pushing it back here. if (Opts.UnrollLoops) @@ -195,6 +207,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-fobjc-dispatch-method=non-legacy"); break; } + if (Opts.NumRegisterParameters) { + Res.push_back("-mregparm"); + Res.push_back(llvm::utostr(Opts.NumRegisterParameters)); + } if (Opts.RelaxAll) Res.push_back("-mrelax-all"); if (Opts.SoftFloat) @@ -213,6 +229,12 @@ static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, std::vector<std::string> &Res) { if (Opts.IncludeSystemHeaders) Res.push_back("-sys-header-deps"); + if (Opts.ShowHeaderIncludes) + Res.push_back("-H"); + if (!Opts.HeaderIncludeOutputFile.empty()) { + Res.push_back("-header-include-file"); + Res.push_back(Opts.HeaderIncludeOutputFile); + } if (Opts.UsePhonyTargets) Res.push_back("-MP"); if (!Opts.OutputFile.empty()) { @@ -251,8 +273,6 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, Res.push_back("-fcolor-diagnostics"); if (Opts.VerifyDiagnostics) Res.push_back("-verify"); - if (Opts.BinaryOutput) - Res.push_back("-fdiagnostics-binary"); if (Opts.ShowOptionNames) Res.push_back("-fdiagnostics-show-option"); if (Opts.ShowCategories == 1) @@ -301,6 +321,7 @@ static const char *getInputKindName(InputKind Kind) { case IK_ObjC: return "objective-c"; case IK_ObjCXX: return "objective-c++"; case IK_OpenCL: return "cl"; + case IK_CUDA: return "cuda"; case IK_PreprocessedC: return "cpp-output"; case IK_PreprocessedCXX: return "c++-cpp-output"; case IK_PreprocessedObjC: return "objective-c-cpp-output"; @@ -314,10 +335,10 @@ static const char *getInputKindName(InputKind Kind) { static const char *getActionName(frontend::ActionKind Kind) { switch (Kind) { case frontend::PluginAction: - case frontend::InheritanceView: llvm_unreachable("Invalid kind!"); case frontend::ASTDump: return "-ast-dump"; + case frontend::ASTDumpXML: return "-ast-dump-xml"; case frontend::ASTPrint: return "-ast-print"; case frontend::ASTPrintXML: return "-ast-print-xml"; case frontend::ASTView: return "-ast-view"; @@ -351,10 +372,16 @@ static const char *getActionName(frontend::ActionKind Kind) { return 0; } +static void FileSystemOptsToArgs(const FileSystemOptions &Opts, + std::vector<std::string> &Res) { + if (!Opts.WorkingDir.empty()) { + Res.push_back("-working-directory"); + Res.push_back(Opts.WorkingDir); + } +} + static void FrontendOptsToArgs(const FrontendOptions &Opts, std::vector<std::string> &Res) { - if (!Opts.DebugCodeCompletionPrinter) - Res.push_back("-no-code-completion-debug-printer"); if (Opts.DisableFree) Res.push_back("-disable-free"); if (Opts.RelocatablePCH) @@ -397,18 +424,13 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-o"); Res.push_back(Opts.OutputFile); } - if (!Opts.ViewClassInheritance.empty()) { - Res.push_back("-cxx-inheritance-view"); - Res.push_back(Opts.ViewClassInheritance); - } if (!Opts.CodeCompletionAt.FileName.empty()) { Res.push_back("-code-completion-at"); Res.push_back(Opts.CodeCompletionAt.FileName + ":" + llvm::utostr(Opts.CodeCompletionAt.Line) + ":" + llvm::utostr(Opts.CodeCompletionAt.Column)); } - if (Opts.ProgramAction != frontend::InheritanceView && - Opts.ProgramAction != frontend::PluginAction) + if (Opts.ProgramAction != frontend::PluginAction) Res.push_back(getActionName(Opts.ProgramAction)); if (!Opts.ActionName.empty()) { Res.push_back("-plugin"); @@ -422,6 +444,14 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-load"); Res.push_back(Opts.Plugins[i]); } + for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { + Res.push_back("-add-plugin"); + Res.push_back(Opts.AddPluginActions[i]); + for(unsigned ai = 0, ae = Opts.AddPluginArgs.size(); ai != ae; ++ai) { + Res.push_back("-plugin-arg-" + Opts.AddPluginActions[i]); + Res.push_back(Opts.AddPluginArgs[i][ai]); + } + } for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) { Res.push_back("-ast-merge"); Res.push_back(Opts.ASTMergeFiles[i]); @@ -443,6 +473,11 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, Res.push_back(Opts.Sysroot); } + for (unsigned i = 0, e = Opts.CXXSystemIncludes.size(); i != e; ++i) { + Res.push_back("-cxx-system-include"); + Res.push_back(Opts.CXXSystemIncludes[i]); + } + /// User specified include entries. for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) { const HeaderSearchOptions::Entry &E = Opts.UserEntries[i]; @@ -526,12 +561,16 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fgnu-keywords"); if (Opts.Microsoft) 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-abi2"); + Res.push_back("-fobjc-nonfragile-abi"); + if (Opts.ObjCDefaultSynthProperties) + Res.push_back("-fobjc-default-synthesize-properties"); // NoInline is implicit. if (!Opts.CXXOperatorNames) Res.push_back("-fno-operator-names"); @@ -551,8 +590,12 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fexceptions"); if (Opts.SjLjExceptions) Res.push_back("-fsjlj-exceptions"); + if (!Opts.ObjCExceptions) + Res.push_back("-fno-objc-exceptions"); if (!Opts.RTTI) Res.push_back("-fno-rtti"); + if (Opts.MSBitfields) + Res.push_back("-mms-bitfields"); if (!Opts.NeXTRuntime) Res.push_back("-fgnu-runtime"); if (Opts.Freestanding) @@ -574,7 +617,12 @@ static void LangOptsToArgs(const LangOptions &Opts, switch (Opts.getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: break; case LangOptions::SOB_Defined: Res.push_back("-fwrapv"); break; - case LangOptions::SOB_Trapping: Res.push_back("-ftrapv"); break; + case LangOptions::SOB_Trapping: + Res.push_back("-ftrapv"); break; + if (!Opts.OverflowHandler.empty()) { + Res.push_back("-ftrapv-handler"); + Res.push_back(Opts.OverflowHandler); + } } if (Opts.HeinousExtensions) Res.push_back("-fheinous-gnu-extensions"); @@ -588,8 +636,6 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fdump-vtable-layouts"); if (Opts.NoBitFieldTypeAlign) Res.push_back("-fno-bitfield-type-alignment"); - if (Opts.SjLjExceptions) - Res.push_back("-fsjlj-exceptions"); if (Opts.PICLevel) { Res.push_back("-pic-level"); Res.push_back(llvm::utostr(Opts.PICLevel)); @@ -614,19 +660,22 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fobjc-gc-only"); } } - if (Opts.getVisibilityMode() != LangOptions::Default) { + if (Opts.AppleKext) + Res.push_back("-fapple-kext"); + + if (Opts.getVisibilityMode() != DefaultVisibility) { Res.push_back("-fvisibility"); - if (Opts.getVisibilityMode() == LangOptions::Hidden) { + if (Opts.getVisibilityMode() == HiddenVisibility) { Res.push_back("hidden"); } else { - assert(Opts.getVisibilityMode() == LangOptions::Protected && + assert(Opts.getVisibilityMode() == ProtectedVisibility && "Invalid visibility!"); Res.push_back("protected"); } } if (Opts.InlineVisibilityHidden) Res.push_back("-fvisibility-inlines-hidden"); - + if (Opts.getStackProtectorMode() != 0) { Res.push_back("-stack-protector"); Res.push_back(llvm::utostr(Opts.getStackProtectorMode())); @@ -692,8 +741,6 @@ static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, else if (!Opts.ShowCPP && Opts.ShowMacros) Res.push_back("-dM"); - if (Opts.ShowHeaderIncludes) - Res.push_back("-H"); if (!Opts.ShowLineMarkers) Res.push_back("-P"); if (Opts.ShowComments) @@ -733,6 +780,7 @@ void CompilerInvocation::toArgs(std::vector<std::string> &Res) { CodeGenOptsToArgs(getCodeGenOpts(), Res); DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res); DiagnosticOptsToArgs(getDiagnosticOpts(), Res); + FileSystemOptsToArgs(getFileSystemOpts(), Res); FrontendOptsToArgs(getFrontendOpts(), Res); HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res); LangOptsToArgs(getLangOpts(), Res); @@ -750,6 +798,16 @@ using namespace clang::driver::cc1options; // +static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, + Diagnostic &Diags) { + unsigned DefaultOpt = 0; + if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable)) + DefaultOpt = 2; + // -Os implies -O2 + return Args.hasArg(OPT_Os) ? 2 : + Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags); +} + static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Diagnostic &Diags) { using namespace cc1options; @@ -810,33 +868,44 @@ 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.AnalyzerStats = Args.hasArg(OPT_analysis_AnalyzerStats); 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); + Opts.CFGAddImplicitDtors = Args.hasArg(OPT_analysis_CFGAddImplicitDtors); + Opts.CFGAddInitializers = Args.hasArg(OPT_analysis_CFGAddInitializers); Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks); Opts.EnableExperimentalInternalChecks = Args.hasArg(OPT_analyzer_experimental_internal_checks); Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); - Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 3, Diags); + Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags); + Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph); Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call); - Opts.IdempotentOps = Args.hasArg(OPT_analysis_WarnIdempotentOps); + Opts.BufferOverflows = Args.hasArg(OPT_analysis_WarnBufferOverflows); + + Opts.CheckersControlList.clear(); + for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker, + OPT_analyzer_disable_checker), + ie = Args.filtered_end(); it != ie; ++it) { + const Arg *A = *it; + A->claim(); + bool enable = (A->getOption().getID() == OPT_analyzer_checker); + Opts.CheckersControlList.push_back(std::make_pair(A->getValue(Args), + enable)); + } } -static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, +static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Diagnostic &Diags) { using namespace cc1options; - // -Os implies -O2 - if (Args.hasArg(OPT_Os)) - Opts.OptimizationLevel = 2; - else { - Opts.OptimizationLevel = Args.getLastArgIntValue(OPT_O, 0, Diags); - if (Opts.OptimizationLevel > 3) { - Diags.Report(diag::err_drv_invalid_value) - << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel; - Opts.OptimizationLevel = 3; - } + + Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags); + if (Opts.OptimizationLevel > 3) { + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel; + Opts.OptimizationLevel = 3; } // We must always run at least the always inlining pass. @@ -844,8 +913,10 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, : CodeGenOptions::OnlyAlwaysInlining; Opts.DebugInfo = Args.hasArg(OPT_g); + Opts.LimitDebugInfo = Args.hasArg(OPT_flimit_debug_info); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); + Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); @@ -853,7 +924,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.OptimizeSize = Args.hasArg(OPT_Os); Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) || Args.hasArg(OPT_ffreestanding)); - Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) || + Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) || (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize); Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); @@ -864,11 +935,17 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim); Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi); Opts.HiddenWeakVTables = Args.hasArg(OPT_fhidden_weak_vtables); + Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable); Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision); + Opts.NoInfsFPMath = Opts.NoNaNsFPMath = Args.hasArg(OPT_cl_finite_math_only)|| + Args.hasArg(OPT_cl_fast_relaxed_math); Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); + Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags); Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer); Opts.SoftFloat = Args.hasArg(OPT_msoft_float); + Opts.UnsafeFPMath = Args.hasArg(OPT_cl_unsafe_math_optimizations) || + Args.hasArg(OPT_cl_fast_relaxed_math); Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); @@ -879,6 +956,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); + Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { llvm::StringRef Name = A->getValue(Args); @@ -901,6 +979,8 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, Opts.Targets = Args.getAllArgValues(OPT_MT); Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps); Opts.UsePhonyTargets = Args.hasArg(OPT_MP); + Opts.ShowHeaderIncludes = Args.hasArg(OPT_H); + Opts.HeaderIncludeOutputFile = Args.getLastArgValue(OPT_header_include_file); } static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, @@ -940,18 +1020,17 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) << ShowCategory; - + Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); - Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary); Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags); Opts.MacroBacktraceLimit - = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit, + = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit, DiagnosticOptions::DefaultMacroBacktraceLimit, Diags); Opts.TemplateBacktraceLimit - = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit, - DiagnosticOptions::DefaultTemplateBacktraceLimit, + = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit, + DiagnosticOptions::DefaultTemplateBacktraceLimit, Diags); Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop, DiagnosticOptions::DefaultTabStop, Diags); @@ -965,6 +1044,10 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.Warnings = Args.getAllArgValues(OPT_W); } +static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) { + Opts.WorkingDir = Args.getLastArgValue(OPT_working_directory); +} + static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { using namespace cc1options; @@ -975,6 +1058,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, assert(0 && "Invalid option in group!"); case OPT_ast_dump: Opts.ProgramAction = frontend::ASTDump; break; + case OPT_ast_dump_xml: + Opts.ProgramAction = frontend::ASTDumpXML; break; case OPT_ast_print: Opts.ProgramAction = frontend::ASTPrint; break; case OPT_ast_print_xml: @@ -1047,6 +1132,16 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, } } + Opts.AddPluginActions = Args.getAllArgValues(OPT_add_plugin); + Opts.AddPluginArgs.resize(Opts.AddPluginActions.size()); + for (int i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { + for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg), + end = Args.filtered_end(); it != end; ++it) { + if ((*it)->getValue(Args, 0) == Opts.AddPluginActions[i]) + Opts.AddPluginArgs[i].push_back((*it)->getValue(Args, 1)); + } + } + if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) { Opts.CodeCompletionAt = ParsedSourceLocation::FromString(A->getValue(Args)); @@ -1054,8 +1149,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(Args); } - Opts.DebugCodeCompletionPrinter = - !Args.hasArg(OPT_no_code_completion_debug_printer); Opts.DisableFree = Args.hasArg(OPT_disable_free); Opts.OutputFile = Args.getLastArgValue(OPT_o); @@ -1071,7 +1164,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ShowStats = Args.hasArg(OPT_print_stats); Opts.ShowTimers = Args.hasArg(OPT_ftime_report); Opts.ShowVersion = Args.hasArg(OPT_version); - Opts.ViewClassInheritance = Args.getLastArgValue(OPT_cxx_inheritance_view); Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge); Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can); @@ -1084,6 +1176,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("cl", IK_OpenCL) .Case("c", IK_C) .Case("cl", IK_OpenCL) + .Case("cuda", IK_CUDA) .Case("c++", IK_CXX) .Case("objective-c", IK_ObjC) .Case("objective-c++", IK_ObjCXX) @@ -1143,6 +1236,7 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0, static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { using namespace cc1options; + Opts.CXXSystemIncludes = Args.getAllArgValues(OPT_cxx_system_include); Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); @@ -1186,10 +1280,8 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { // FIXME: Need options for the various environment variables! } -static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, - Diagnostic &Diags) { - // FIXME: Cleanup per-file based stuff. - +void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, + LangStandard::Kind LangStd) { // Set some properties which depend soley on the input kind; it would be nice // to move these to the language standard, and have the driver resolve the // input kind + language standard. @@ -1202,18 +1294,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.ObjC1 = Opts.ObjC2 = 1; } - LangStandard::Kind LangStd = LangStandard::lang_unspecified; - if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { - LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args)) -#define LANGSTANDARD(id, name, desc, features) \ - .Case(name, LangStandard::lang_##id) -#include "clang/Frontend/LangStandards.def" - .Default(LangStandard::lang_unspecified); - if (LangStd == LangStandard::lang_unspecified) - Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(Args); - } - if (LangStd == LangStandard::lang_unspecified) { // Based on the base language, pick one. switch (IK) { @@ -1224,6 +1304,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, case IK_OpenCL: LangStd = LangStandard::lang_opencl; break; + case IK_CUDA: + LangStd = LangStandard::lang_cuda; + break; case IK_Asm: case IK_C: case IK_PreprocessedC: @@ -1257,26 +1340,71 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.AltiVec = 1; Opts.CXXOperatorNames = 1; Opts.LaxVectorConversions = 1; + Opts.DefaultFPContract = 1; } + if (LangStd == LangStandard::lang_cuda) + Opts.CUDA = 1; + // OpenCL and C++ both have bool, true, false keywords. Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + Opts.GNUKeywords = Opts.GNUMode; + Opts.CXXOperatorNames = Opts.CPlusPlus; + + // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs + // is specified, or -std is set to a conforming mode. + Opts.Trigraphs = !Opts.GNUMode; + + Opts.DollarIdents = !Opts.AsmPreprocessor; +} + +static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, + Diagnostic &Diags) { + // FIXME: Cleanup per-file based stuff. + LangStandard::Kind LangStd = LangStandard::lang_unspecified; + if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { + LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args)) +#define LANGSTANDARD(id, name, desc, features) \ + .Case(name, LangStandard::lang_##id) +#include "clang/Frontend/LangStandards.def" + .Default(LangStandard::lang_unspecified); + if (LangStd == LangStandard::lang_unspecified) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + + if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) { + if (strcmp(A->getValue(Args), "CL1.1") != 0) { + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + } + + CompilerInvocation::setLangDefaults(Opts, IK, LangStd); + // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension // keywords. This behavior is provided by GCC's poorly named '-fasm' flag, // while a subset (the non-C++ GNU keywords) is provided by GCC's // '-fgnu-keywords'. Clang conflates the two for simplicity under the single // name, as it doesn't seem a useful distinction. Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords, - Opts.GNUMode); + Opts.GNUKeywords); - if (Opts.CPlusPlus) - Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names); + if (Args.hasArg(OPT_fno_operator_names)) + Opts.CXXOperatorNames = 0; if (Args.hasArg(OPT_fobjc_gc_only)) Opts.setGCMode(LangOptions::GCOnly); else if (Args.hasArg(OPT_fobjc_gc)) Opts.setGCMode(LangOptions::HybridGC); + + if (Args.hasArg(OPT_fapple_kext)) { + if (!Opts.CPlusPlus) + Diags.Report(diag::warn_c_kext); + else + Opts.AppleKext = 1; + } if (Args.hasArg(OPT_print_ivar_layout)) Opts.ObjCGCBitmapPrint = 1; @@ -1291,34 +1419,36 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); if (Vis == "default") - Opts.setVisibilityMode(LangOptions::Default); + Opts.setVisibilityMode(DefaultVisibility); else if (Vis == "hidden") - Opts.setVisibilityMode(LangOptions::Hidden); + Opts.setVisibilityMode(HiddenVisibility); else if (Vis == "protected") - Opts.setVisibilityMode(LangOptions::Protected); + Opts.setVisibilityMode(ProtectedVisibility); else Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; if (Args.hasArg(OPT_fvisibility_inlines_hidden)) Opts.InlineVisibilityHidden = 1; - - if (Args.hasArg(OPT_ftrapv)) - Opts.setSignedOverflowBehavior(LangOptions::SOB_Trapping); + + if (Args.hasArg(OPT_ftrapv)) { + Opts.setSignedOverflowBehavior(LangOptions::SOB_Trapping); + // Set the handler, if one is specified. + Opts.OverflowHandler = + Args.getLastArgValue(OPT_ftrapv_handler); + } else if (Args.hasArg(OPT_fwrapv)) - Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined); + Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined); - // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs - // is specified, or -std is set to a conforming mode. - Opts.Trigraphs = !Opts.GNUMode; if (Args.hasArg(OPT_trigraphs)) Opts.Trigraphs = 1; Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers, OPT_fno_dollars_in_identifiers, - !Opts.AsmPreprocessor); + Opts.DollarIdents); Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); Opts.Microsoft = Args.hasArg(OPT_fms_extensions); + Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags); Opts.Borland = Args.hasArg(OPT_fborland_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings); @@ -1327,10 +1457,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fno_threadsafe_statics)) Opts.ThreadsafeStatics = 0; Opts.Exceptions = Args.hasArg(OPT_fexceptions); + Opts.ObjCExceptions = !Args.hasArg(OPT_fno_objc_exceptions); Opts.RTTI = !Args.hasArg(OPT_fno_rtti); Opts.Blocks = Args.hasArg(OPT_fblocks); Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); + Opts.ShortEnums = Args.hasArg(OPT_fshort_enums); Opts.Freestanding = Args.hasArg(OPT_ffreestanding); Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); @@ -1340,27 +1472,33 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.MathErrno = Args.hasArg(OPT_fmath_errno); Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024, Diags); + Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy, + 0, Diags); + Opts.MSBitfields = Args.hasArg(OPT_mms_bitfields); Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); Opts.ObjCConstantStringClass = Args.getLastArgValue(OPT_fconstant_string_class); Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); - Opts.ObjCNonFragileABI2 = Args.hasArg(OPT_fobjc_nonfragile_abi2); - if (Opts.ObjCNonFragileABI2) - Opts.ObjCNonFragileABI = true; + 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.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags); Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions); + Opts.ObjCExceptions = !Args.hasArg(OPT_fno_objc_exceptions); Opts.Static = Args.hasArg(OPT_static_define); Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts); Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts); Opts.SpellChecking = !Args.hasArg(OPT_fno_spell_checking); Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align); + Opts.SinglePrecisionConstants = Args.hasArg(OPT_cl_single_precision_constant); + Opts.FastRelaxedMath = Args.hasArg(OPT_cl_fast_relaxed_math); Opts.OptimizeSize = 0; // FIXME: Eliminate this dependency. - unsigned Opt = - Args.hasArg(OPT_Os) ? 2 : Args.getLastArgIntValue(OPT_O, 0, Diags); + unsigned Opt = getOptimizationLevel(Args, IK, Diags); Opts.Optimize = Opt != 0; // This is the __NO_INLINE__ define, which just depends on things like the @@ -1383,6 +1521,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, + FileManager &FileMgr, Diagnostic &Diags) { using namespace cc1options; Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); @@ -1395,12 +1534,19 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch); + Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls); + for (arg_iterator it = Args.filtered_begin(OPT_error_on_deserialized_pch_decl), + ie = Args.filtered_end(); it != ie; ++it) { + const Arg *A = *it; + Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue(Args)); + } + if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { llvm::StringRef Value(A->getValue(Args)); size_t Comma = Value.find(','); unsigned Bytes = 0; unsigned EndOfLine = 0; - + if (Comma == llvm::StringRef::npos || Value.substr(0, Comma).getAsInteger(10, Bytes) || Value.substr(Comma + 1).getAsInteger(10, EndOfLine)) @@ -1410,7 +1556,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.PrecompiledPreambleBytes.second = (EndOfLine != 0); } } - + // Add macros from the command line. for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U), ie = Args.filtered_end(); it != ie; ++it) { @@ -1430,7 +1576,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, // PCH is handled specially, we need to extra the original include path. if (A->getOption().matches(OPT_include_pch)) { std::string OriginalFile = - ASTReader::getOriginalSourceFile(A->getValue(Args), Diags); + ASTReader::getOriginalSourceFile(A->getValue(Args), FileMgr, Diags); if (OriginalFile.empty()) continue; @@ -1463,7 +1609,6 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, using namespace cc1options; Opts.ShowCPP = !Args.hasArg(OPT_dM); Opts.ShowComments = Args.hasArg(OPT_C); - Opts.ShowHeaderIncludes = Args.hasArg(OPT_H); Opts.ShowLineMarkers = !Args.hasArg(OPT_P); Opts.ShowMacroComments = Args.hasArg(OPT_CC); Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD); @@ -1486,8 +1631,8 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { // void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, - const char **ArgBegin, - const char **ArgEnd, + const char *const *ArgBegin, + const char *const *ArgEnd, Diagnostic &Diags) { // Parse the arguments. llvm::OwningPtr<OptTable> Opts(createCC1OptTable()); @@ -1506,14 +1651,21 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Diags.Report(diag::err_drv_unknown_argument) << (*it)->getAsString(*Args); ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags); - ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, Diags); ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags); + ParseFileSystemArgs(Res.getFileSystemOpts(), *Args); + // FIXME: We shouldn't have to pass the DashX option around here InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); + ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags); ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args); if (DashX != IK_AST && DashX != IK_LLVM_IR) ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags); - ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, Diags); + // FIXME: ParsePreprocessorArgs uses the FileManager to read the contents of + // PCH file and find the original header name. Remove the need to do that in + // ParsePreprocessorArgs and remove the FileManager + // parameters from the function and the "FileManager.h" #include. + FileManager FileMgr(Res.getFileSystemOpts()); + ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); ParseTargetArgs(Res.getTargetOpts(), *Args); } diff --git a/lib/Frontend/DeclXML.cpp b/lib/Frontend/DeclXML.cpp index 97a7f55..8d3d225 100644 --- a/lib/Frontend/DeclXML.cpp +++ b/lib/Frontend/DeclXML.cpp @@ -38,10 +38,12 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> { } void addSubNodes(RecordDecl* RD) { - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - Visit(*i); - Doc.toParent(); + for (RecordDecl::decl_iterator i = RD->decls_begin(), + e = RD->decls_end(); i != e; ++i) { + if (!(*i)->isImplicit()) { + Visit(*i); + Doc.toParent(); + } } } @@ -71,15 +73,7 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> { Doc.addAttribute("is_virtual", base->isVirtual()); Doc.toParent(); } - - for (CXXRecordDecl::method_iterator i = RD->method_begin(), - e = RD->method_end(); i != e; ++i) { - Visit(*i); - Doc.toParent(); - } - } - } void addSubNodes(EnumDecl* ED) { @@ -110,7 +104,7 @@ class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> { Doc.PrintStmt(argDecl->getDefaultArg()); } - void addSubNodes(NamespaceDecl* ns) { + void addSubNodes(DeclContext* ns) { for (DeclContext::decl_iterator d = ns->decls_begin(), diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index cdff807..bc5a55d 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -13,7 +13,6 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/DependencyOutputOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -22,7 +21,6 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/raw_ostream.h" -#include <string> using namespace clang; @@ -117,6 +115,16 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc, 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) { + for (unsigned i = 0, e = Filename.size(); i != e; ++i) { + if (Filename[i] == ' ') + OS << '\\'; + OS << Filename[i]; + } +} + void DependencyFileCallback::OutputDependencyFile() { // Write out the dependency targets, trying to avoid overly long // lines when possible. We try our best to emit exactly the same @@ -130,14 +138,15 @@ void DependencyFileCallback::OutputDependencyFile() { unsigned N = I->length(); if (Columns == 0) { Columns += N; - *OS << *I; } else if (Columns + N + 2 > MaxColumns) { Columns = N + 2; - *OS << " \\\n " << *I; + *OS << " \\\n "; } else { Columns += N + 1; - *OS << ' ' << *I; + *OS << ' '; } + // Targets already quoted as needed. + *OS << *I; } *OS << ':'; @@ -155,7 +164,8 @@ void DependencyFileCallback::OutputDependencyFile() { *OS << " \\\n "; Columns = 2; } - *OS << ' ' << *I; + *OS << ' '; + PrintFilename(*OS, *I); Columns += N + 1; } *OS << '\n'; @@ -166,7 +176,8 @@ void DependencyFileCallback::OutputDependencyFile() { for (std::vector<std::string>::iterator I = Files.begin() + 1, E = Files.end(); I != E; ++I) { *OS << '\n'; - *OS << *I << ":\n"; + PrintFilename(*OS, *I); + *OS << ":\n"; } } } diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp index 894f230..b24ece5 100644 --- a/lib/Frontend/DocumentXML.cpp +++ b/lib/Frontend/DocumentXML.cpp @@ -17,6 +17,8 @@ #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Config/config.h" +#include <cstdio> namespace clang { @@ -104,7 +106,11 @@ std::string DocumentXML::escapeString(const char* pStr, if (isprint(C)) value += C; else { +#ifdef LLVM_ON_WIN32 sprintf(buffer, "\\%03o", C); +#else + snprintf(buffer, sizeof(buffer), "\\%03o", C); +#endif value += buffer; } break; @@ -321,9 +327,11 @@ PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc) if (!SpellingLoc.isInvalid()) { PLoc = SM.getPresumedLoc(SpellingLoc); - addSourceFileAttribute(PLoc.getFilename()); - addAttribute("line", PLoc.getLine()); - addAttribute("col", PLoc.getColumn()); + if (PLoc.isValid()) { + addSourceFileAttribute(PLoc.getFilename()); + addAttribute("line", PLoc.getLine()); + addAttribute("col", PLoc.getColumn()); + } } // else there is no error in some cases (eg. CXXThisExpr) return PLoc; @@ -340,8 +348,9 @@ void DocumentXML::addLocationRange(const SourceRange& R) if (!SpellingLoc.isInvalid()) { PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc); - if (PStartLoc.isInvalid() || - strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) { + if (PLoc.isInvalid()) { + } else if (PStartLoc.isInvalid() || + strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) { addToMap(SourceFiles, PLoc.getFilename(), ID_FILE); addAttribute("endfile", PLoc.getFilename()); addAttribute("endline", PLoc.getLine()); diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index b244c5c..e3d8b85 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -10,18 +10,73 @@ #include "clang/Frontend/FrontendAction.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclGroup.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/Frontend/MultiplexConsumer.h" #include "clang/Parse/ParseAST.h" +#include "clang/Serialization/ASTDeserializationListener.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +namespace { + +/// \brief Dumps deserialized declarations. +class DeserializedDeclsDumper : public ASTDeserializationListener { + ASTDeserializationListener *Previous; + +public: + DeserializedDeclsDumper(ASTDeserializationListener *Previous) + : Previous(Previous) { } + + virtual void DeclRead(serialization::DeclID ID, const Decl *D) { + llvm::outs() << "PCH DECL: " << D->getDeclKindName(); + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) + llvm::outs() << " - " << ND->getNameAsString(); + llvm::outs() << "\n"; + + if (Previous) + Previous->DeclRead(ID, D); + } +}; + + /// \brief Checks deserialized declarations and emits error if a name + /// matches one given in command-line using -error-on-deserialized-decl. + class DeserializedDeclsChecker : public ASTDeserializationListener { + ASTContext &Ctx; + std::set<std::string> NamesToCheck; + ASTDeserializationListener *Previous; + + public: + DeserializedDeclsChecker(ASTContext &Ctx, + const std::set<std::string> &NamesToCheck, + ASTDeserializationListener *Previous) + : Ctx(Ctx), NamesToCheck(NamesToCheck), Previous(Previous) { } + + virtual void DeclRead(serialization::DeclID ID, const Decl *D) { + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) { + unsigned DiagID + = Ctx.getDiagnostics().getCustomDiagID(Diagnostic::Error, + "%0 was deserialized"); + Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID) + << ND->getNameAsString(); + } + + if (Previous) + Previous->DeclRead(ID, D); + } +}; + +} // end anonymous namespace + FrontendAction::FrontendAction() : Instance(0) {} FrontendAction::~FrontendAction() {} @@ -33,6 +88,39 @@ void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind, CurrentASTUnit.reset(AST); } +ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + ASTConsumer* Consumer = CreateASTConsumer(CI, InFile); + if (!Consumer) + return 0; + + if (CI.getFrontendOpts().AddPluginActions.size() == 0) + return Consumer; + + // Make sure the non-plugin consumer is first, so that plugins can't + // modifiy the AST. + std::vector<ASTConsumer*> Consumers(1, Consumer); + + for (size_t i = 0, e = CI.getFrontendOpts().AddPluginActions.size(); + i != e; ++i) { + // This is O(|plugins| * |add_plugins|), but since both numbers are + // way below 50 in practice, that's ok. + for (FrontendPluginRegistry::iterator + it = FrontendPluginRegistry::begin(), + ie = FrontendPluginRegistry::end(); + it != ie; ++it) { + if (it->getName() == CI.getFrontendOpts().AddPluginActions[i]) { + llvm::OwningPtr<PluginASTAction> P(it->instantiate()); + FrontendAction* c = P.get(); + if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i])) + Consumers.push_back(c->CreateASTConsumer(CI, InFile)); + } + } + } + + return new MultiplexConsumer(Consumers); +} + bool FrontendAction::BeginSourceFile(CompilerInstance &CI, llvm::StringRef Filename, InputKind InputKind) { @@ -51,7 +139,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics()); std::string Error; - ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags); + ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags, + CI.getFileSystemOpts()); if (!AST) goto failure; @@ -69,7 +158,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, goto failure; /// Create the AST consumer. - CI.setASTConsumer(CreateASTConsumer(CI, Filename)); + CI.setASTConsumer(CreateWrappedASTConsumer(CI, Filename)); if (!CI.hasASTConsumer()) goto failure; @@ -80,7 +169,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!CI.hasFileManager()) CI.createFileManager(); if (!CI.hasSourceManager()) - CI.createSourceManager(); + CI.createSourceManager(CI.getFileManager()); // IR files bypass the rest of initialization. if (InputKind == IK_LLVM_IR) { @@ -113,16 +202,30 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!usesPreprocessorOnly()) { CI.createASTContext(); - llvm::OwningPtr<ASTConsumer> Consumer(CreateASTConsumer(CI, Filename)); + llvm::OwningPtr<ASTConsumer> Consumer( + CreateWrappedASTConsumer(CI, Filename)); + if (!Consumer) + goto failure; + + CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener()); /// Use PCH? if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { assert(hasPCHSupport() && "This action does not have PCH support!"); + ASTDeserializationListener *DeserialListener + = CI.getInvocation().getFrontendOpts().ChainedPCH ? + Consumer->GetASTDeserializationListener() : 0; + if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls) + DeserialListener = new DeserializedDeclsDumper(DeserialListener); + if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty()) + DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(), + CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn, + DeserialListener); CI.createPCHExternalASTSource( CI.getPreprocessorOpts().ImplicitPCHInclude, CI.getPreprocessorOpts().DisablePCHValidation, - CI.getInvocation().getFrontendOpts().ChainedPCH? - Consumer->GetASTDeserializationListener() : 0); + CI.getPreprocessorOpts().DisableStatCache, + DeserialListener); if (!CI.getASTContext().getExternalSource()) goto failure; } @@ -137,7 +240,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { Preprocessor &PP = CI.getPreprocessor(); PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), - PP.getLangOptions().NoBuiltin); + PP.getLangOptions()); } return true; @@ -187,6 +290,9 @@ void FrontendAction::Execute() { void FrontendAction::EndSourceFile() { CompilerInstance &CI = getCompilerInstance(); + // Inform the diagnostic client we are done with this source file. + CI.getDiagnosticClient().EndSourceFile(); + // Finalize the action. EndSourceFileAction(); @@ -223,10 +329,7 @@ void FrontendAction::EndSourceFile() { // Cleanup the output streams, and erase the output files if we encountered // an error. - CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors()); - - // Inform the diagnostic client we are done with this source file. - CI.getDiagnosticClient().EndSourceFile(); + CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().hasErrorOccurred()); if (isCurrentFileAST()) { CI.takeSema(); diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 5bc6506..d8e7d29 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -59,6 +59,17 @@ ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, return CreateASTDumper(); } +ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + llvm::raw_ostream *OS; + if (CI.getFrontendOpts().OutputFile.empty()) + OS = &llvm::outs(); + else + OS = CI.createDefaultOutputFile(false, InFile); + if (!OS) return 0; + return CreateASTDumperXML(*OS); +} + ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { return CreateASTViewer(); @@ -72,19 +83,21 @@ ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { std::string Sysroot; + std::string OutputFile; llvm::raw_ostream *OS = 0; bool Chaining; - if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OS, Chaining)) + if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS, Chaining)) return 0; const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? Sysroot.c_str() : 0; - return new PCHGenerator(CI.getPreprocessor(), Chaining, isysroot, OS); + return new PCHGenerator(CI.getPreprocessor(), OutputFile, Chaining, isysroot, OS); } bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, llvm::StringRef InFile, std::string &Sysroot, + std::string &OutputFile, llvm::raw_ostream *&OS, bool &Chaining) { Sysroot = CI.getHeaderSearchOpts().Sysroot; @@ -93,20 +106,19 @@ bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, return true; } - OS = CI.createDefaultOutputFile(true, InFile); + // We use createOutputFile here because this is exposed via libclang, and we + // must disable the RemoveFileOnSignal behavior. + OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true, + /*RemoveFileOnSignal=*/false, InFile); if (!OS) return true; + OutputFile = CI.getFrontendOpts().OutputFile; Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH && !CI.getPreprocessorOpts().ImplicitPCHInclude.empty(); return false; } -ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance); -} - ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { return new ASTConsumer(); @@ -193,6 +205,7 @@ void PrintPreambleAction::ExecuteAction() { case IK_ObjC: case IK_ObjCXX: case IK_OpenCL: + case IK_CUDA: break; case IK_None: @@ -207,7 +220,9 @@ void PrintPreambleAction::ExecuteAction() { return; } - llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getFile(getCurrentFile()); + CompilerInstance &CI = getCompilerInstance(); + llvm::MemoryBuffer *Buffer + = CI.getFileManager().getBufferForFile(getCurrentFile()); if (Buffer) { unsigned Preamble = Lexer::ComputePreamble(Buffer).first; llvm::outs().write(Buffer->getBufferStart(), Preamble); diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 9dfee24..0a20051 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -26,6 +26,7 @@ InputKind FrontendOptions::getInputKindForExtension(llvm::StringRef Extension) { .Cases("C", "cc", "cp", IK_CXX) .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX) .Case("cl", IK_OpenCL) + .Case("cu", IK_CUDA) .Cases("ll", "bc", IK_LLVM_IR) .Default(IK_C); } diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp new file mode 100644 index 0000000..45ff1d2 --- /dev/null +++ b/lib/Frontend/HeaderIncludeGen.cpp @@ -0,0 +1,113 @@ +//===--- HeaderIncludes.cpp - Generate Header Includes --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/Utils.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { +class HeaderIncludesCallback : public PPCallbacks { + SourceManager &SM; + llvm::raw_ostream *OutputFile; + unsigned CurrentIncludeDepth; + bool HasProcessedPredefines; + bool OwnsOutputFile; + bool ShowAllHeaders; + +public: + HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_, + llvm::raw_ostream *OutputFile_, bool OwnsOutputFile_) + : SM(PP->getSourceManager()), OutputFile(OutputFile_), + CurrentIncludeDepth(0), HasProcessedPredefines(false), + OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_) {} + + ~HeaderIncludesCallback() { + if (OwnsOutputFile) + delete OutputFile; + } + + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType); +}; +} + +void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders, + llvm::StringRef OutputPath) { + llvm::raw_ostream *OutputFile = &llvm::errs(); + bool OwnsOutputFile = false; + + // Open the output file, if used. + if (!OutputPath.empty()) { + std::string Error; + llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream( + OutputPath.str().c_str(), Error, llvm::raw_fd_ostream::F_Append); + if (!Error.empty()) { + PP.getDiagnostics().Report( + clang::diag::warn_fe_cc_print_header_failure) << Error; + delete OS; + } else { + OS->SetUnbuffered(); + OS->SetUseAtomicWrites(true); + OutputFile = OS; + OwnsOutputFile = true; + } + } + + PP.addPPCallbacks(new HeaderIncludesCallback(&PP, ShowAllHeaders, + OutputFile, OwnsOutputFile)); +} + +void HeaderIncludesCallback::FileChanged(SourceLocation Loc, + FileChangeReason Reason, + SrcMgr::CharacteristicKind NewFileType) { + // Unless we are exiting a #include, make sure to skip ahead to the line the + // #include directive was at. + PresumedLoc UserLoc = SM.getPresumedLoc(Loc); + if (UserLoc.isInvalid()) + return; + + // Adjust the current include depth. + if (Reason == PPCallbacks::EnterFile) { + ++CurrentIncludeDepth; + } else { + if (CurrentIncludeDepth) + --CurrentIncludeDepth; + + // We track when we are done with the predefines by watching for the first + // place where we drop back to a nesting depth of 0. + if (CurrentIncludeDepth == 0 && !HasProcessedPredefines) + HasProcessedPredefines = true; + } + + // Show the header if we are (a) past the predefines, or (b) showing all + // headers and in the predefines at a depth past the initial file and command + // line buffers. + bool ShowHeader = (HasProcessedPredefines || + (ShowAllHeaders && CurrentIncludeDepth > 2)); + + // Dump the header include information we are past the predefines buffer or + // are showing all headers. + if (ShowHeader && Reason == PPCallbacks::EnterFile) { + // Write to a temporary string to avoid unnecessary flushing on errs(). + llvm::SmallString<512> Filename(UserLoc.getFilename()); + Lexer::Stringify(Filename); + + llvm::SmallString<256> Msg; + for (unsigned i = 0; i != CurrentIncludeDepth; ++i) + Msg += '.'; + Msg += ' '; + Msg += Filename; + Msg += '\n'; + + OutputFile->write(Msg.data(), Msg.size()); + } +} diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index df91713..4855b62 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -11,6 +11,10 @@ // //===----------------------------------------------------------------------===// +#ifdef HAVE_CLANG_CONFIG_H +# include "clang/Config/config.h" +#endif + #include "clang/Frontend/Utils.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" @@ -23,7 +27,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include "llvm/Config/config.h" #ifdef _MSC_VER #define WIN32_LEAN_AND_MEAN 1 @@ -41,13 +45,15 @@ class InitHeaderSearch { std::vector<DirectoryLookup> IncludeGroup[4]; HeaderSearch& Headers; bool Verbose; - std::string isysroot; + std::string IncludeSysroot; + bool IsNotEmptyOrRoot; public: - InitHeaderSearch(HeaderSearch &HS, - bool verbose = false, const std::string &iSysroot = "") - : Headers(HS), Verbose(verbose), isysroot(iSysroot) {} + InitHeaderSearch(HeaderSearch &HS, bool verbose, llvm::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, @@ -62,7 +68,7 @@ public: llvm::StringRef Dir64, const llvm::Triple &triple); - /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW + /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to support a MinGW /// libstdc++. void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, llvm::StringRef Arch, @@ -101,19 +107,18 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, FileManager &FM = Headers.getFileMgr(); // Compute the actual path, taking into consideration -isysroot. - llvm::SmallString<256> MappedPathStr; - llvm::raw_svector_ostream MappedPath(MappedPathStr); + llvm::SmallString<256> MappedPathStorage; + llvm::StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); // Handle isysroot. - if (Group == System && !IgnoreSysRoot) { - // FIXME: Portability. This should be a sys::Path interface, this doesn't - // handle things like C:\ right, nor win32 \\network\device\blah. - if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present. - MappedPath << isysroot; + if (Group == System && !IgnoreSysRoot && + llvm::sys::path::is_absolute(MappedPathStr) && + IsNotEmptyOrRoot) { + MappedPathStorage.clear(); + MappedPathStr = + (IncludeSysroot + Path).toStringRef(MappedPathStorage); } - Path.print(MappedPath); - // Compute the DirectoryLookup type. SrcMgr::CharacteristicKind Type; if (Group == Quoted || Group == Angled) @@ -125,7 +130,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, // If the directory exists, add it. - if (const DirectoryEntry *DE = FM.getDirectory(MappedPath.str())) { + if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) { IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied, isFramework)); return; @@ -134,7 +139,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, // Check to see if this is an apple-style headermap (which are not allowed to // be frameworks). if (!isFramework) { - if (const FileEntry *FE = FM.getFile(MappedPath.str())) { + if (const FileEntry *FE = FM.getFile(MappedPathStr)) { if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) { // It is a headermap, add it to the search path. IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied)); @@ -145,7 +150,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, if (Verbose) llvm::errs() << "ignoring nonexistent directory \"" - << MappedPath.str() << "\"\n"; + << MappedPathStr << "\"\n"; } @@ -191,8 +196,6 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, llvm::StringRef Arch, llvm::StringRef Version) { - AddPath(Base + "/" + Arch + "/" + Version + "/include", - System, true, false, false); AddPath(Base + "/" + Arch + "/" + Version + "/include/c++", System, true, false, false); AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch, @@ -344,7 +347,7 @@ static bool getVisualStudioDir(std::string &path) { bool hasVCExpressDir = getSystemRegistryString( "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION", "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1); - // If we have both vc80 and vc90, pick version we were compiled with. + // If we have both vc80 and vc90, pick version we were compiled with. if (hasVCDir && vsIDEInstallDir[0]) { char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE"); if (p) @@ -366,7 +369,7 @@ static bool getVisualStudioDir(std::string &path) { const char* vs80comntools = getenv("VS80COMNTOOLS"); const char* vscomntools = NULL; - // Try to find the version that we were compiled with + // Try to find the version that we were compiled with if(false) {} #if (_MSC_VER >= 1600) // VC100 else if(vs100comntools) { @@ -409,7 +412,7 @@ static bool getWindowsSDKDir(std::string &path) { bool hasSDKDir = getSystemRegistryString( "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", "InstallationFolder", windowsSDKInstallDir, sizeof(windowsSDKInstallDir) - 1); - // If we have both vc80 and vc90, pick version we were compiled with. + // If we have both vc80 and vc90, pick version we were compiled with. if (hasSDKDir && windowsSDKInstallDir[0]) { path = windowsSDKInstallDir; return(true); @@ -419,8 +422,16 @@ static bool getWindowsSDKDir(std::string &path) { void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { - // FIXME: temporary hack: hard-coded paths. - AddPath("/usr/local/include", System, true, false, false); + llvm::Triple::OSType os = triple.getOS(); + + switch (os) { + 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 // just prior C include dirs. @@ -439,47 +450,39 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, CIncludeDirs.split(dirs, ":"); for (llvm::SmallVectorImpl<llvm::StringRef>::iterator i = dirs.begin(); i != dirs.end(); - ++i) + ++i) AddPath(*i, System, false, false, false); return; } - llvm::Triple::OSType os = triple.getOS(); + switch (os) { - case llvm::Triple::Win32: - { - std::string VSDir; - std::string WindowsSDKDir; - if (getVisualStudioDir(VSDir)) { - AddPath(VSDir + "\\VC\\include", System, false, false, false); - if (getWindowsSDKDir(WindowsSDKDir)) - AddPath(WindowsSDKDir + "\\include", System, false, false, false); - else - AddPath(VSDir + "\\VC\\PlatformSDK\\Include", - System, false, false, false); - } - else { - // Default install paths. - AddPath("C:/Program Files/Microsoft Visual Studio 10.0/VC/include", - System, false, false, false); - AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include", - System, false, false, false); - AddPath( + case llvm::Triple::Win32: { + std::string VSDir; + std::string WindowsSDKDir; + if (getVisualStudioDir(VSDir)) { + AddPath(VSDir + "\\VC\\include", System, false, false, false); + if (getWindowsSDKDir(WindowsSDKDir)) + AddPath(WindowsSDKDir + "\\include", System, false, false, false); + else + AddPath(VSDir + "\\VC\\PlatformSDK\\Include", + System, false, false, false); + } else { + // Default install paths. + AddPath("C:/Program Files/Microsoft Visual Studio 10.0/VC/include", + System, false, false, false); + AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include", + System, false, false, false); + AddPath( "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include", - System, false, false, false); - AddPath("C:/Program Files/Microsoft Visual Studio 8/VC/include", - System, false, false, false); - AddPath( + System, false, false, false); + AddPath("C:/Program Files/Microsoft Visual Studio 8/VC/include", + System, false, false, false); + AddPath( "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include", - System, false, false, false); - // For some clang developers. - AddPath("G:/Program Files/Microsoft Visual Studio 9.0/VC/include", - System, false, false, false); - AddPath( - "G:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include", - System, false, false, false); - } + System, false, false, false); } break; + } case llvm::Triple::Haiku: AddPath("/boot/common/include", System, true, false, false); AddPath("/boot/develop/headers/os", System, true, false, false); @@ -487,7 +490,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, AddPath("/boot/develop/headers/os/arch", System, true, false, false); AddPath("/boot/develop/headers/os/device", System, true, false, false); AddPath("/boot/develop/headers/os/drivers", System, true, false, false); - AddPath("/boot/develop/headers/os/game", System, true, false, false); + AddPath("/boot/develop/headers/os/game", System, true, false, false); AddPath("/boot/develop/headers/os/interface", System, true, false, false); AddPath("/boot/develop/headers/os/kernel", System, true, false, false); AddPath("/boot/develop/headers/os/locale", System, true, false, false); @@ -500,13 +503,13 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, AddPath("/boot/develop/headers/os/support", System, true, false, false); AddPath("/boot/develop/headers/os/translation", System, true, false, false); - AddPath("/boot/develop/headers/os/add-ons/graphics", + AddPath("/boot/develop/headers/os/add-ons/graphics", System, true, false, false); - AddPath("/boot/develop/headers/os/add-ons/input_server", + AddPath("/boot/develop/headers/os/add-ons/input_server", System, true, false, false); - AddPath("/boot/develop/headers/os/add-ons/screen_saver", + AddPath("/boot/develop/headers/os/add-ons/screen_saver", System, true, false, false); - AddPath("/boot/develop/headers/os/add-ons/tracker", + AddPath("/boot/develop/headers/os/add-ons/tracker", System, true, false, false); AddPath("/boot/develop/headers/os/be_apps/Deskbar", System, true, false, false); @@ -515,7 +518,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, AddPath("/boot/develop/headers/os/be_apps/Tracker", System, true, false, false); AddPath("/boot/develop/headers/cpp", System, true, false, false); - AddPath("/boot/develop/headers/cpp/i586-pc-haiku", + AddPath("/boot/develop/headers/cpp/i586-pc-haiku", System, true, false, false); AddPath("/boot/develop/headers/3rdparty", System, true, false, false); AddPath("/boot/develop/headers/bsd", System, true, false, false); @@ -523,7 +526,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, AddPath("/boot/develop/headers/posix", System, true, false, false); AddPath("/boot/develop/headers", System, true, false, false); break; - case llvm::Triple::MinGW64: + case llvm::Triple::Cygwin: + AddPath("/usr/include/w32api", System, true, false, false); + break; case llvm::Triple::MinGW32: AddPath("c:/mingw/include", System, true, false, false); break; @@ -553,24 +558,24 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { // FIXME: temporary hack: hard-coded paths. switch (os) { case llvm::Triple::Cygwin: - AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include", - System, true, false, false); - AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++", - System, true, false, false); - AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/i686-pc-cygwin", - System, true, false, false); + // Cygwin-1.7 + AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4"); + // g++-4 / Cygwin-1.5 + AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2"); + // FIXME: Do we support g++-3.4.4? + AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "3.4.4"); break; - case llvm::Triple::MinGW64: - // Try gcc 4.5.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.5.0"); - // Try gcc 4.4.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0"); - // Try gcc 4.3.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0"); - // Fall through. case llvm::Triple::MinGW32: - // Try gcc 4.5.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0"); + // mingw-w64-20110207 + AddPath("c:/MinGW/include/c++/4.5.3", System, true, false, false); + AddPath("c:/MinGW/include/c++/4.5.3/x86_64-w64-mingw32", System, true, false, false); + AddPath("c:/MinGW/include/c++/4.5.3/backward", System, true, false, false); + // mingw-w64-20101129 + AddPath("c:/MinGW/include/c++/4.5.2", System, true, false, false); + AddPath("c:/MinGW/include/c++/4.5.2/x86_64-w64-mingw32", System, true, false, false); + AddPath("c:/MinGW/include/c++/4.5.2/backward", System, true, false, false); + // Try gcc 4.5.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0"); // Try gcc 4.4.0 AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); // Try gcc 4.3.0 @@ -580,13 +585,13 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { switch (triple.getArch()) { default: break; - case llvm::Triple::ppc: + case llvm::Triple::ppc: case llvm::Triple::ppc64: AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "powerpc-apple-darwin10", "", "ppc64", + "powerpc-apple-darwin10", "", "ppc64", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", - "powerpc-apple-darwin10", "", "ppc64", + "powerpc-apple-darwin10", "", "ppc64", triple); break; @@ -615,6 +620,11 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { // Debian based distros. // Note: these distros symlink /usr/include/c++/X.Y.Z -> X.Y //===------------------------------------------------------------------===// + // Ubuntu 10.10 "Maverick Meerkat" -- gcc-4.4.5 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", + "i686-linux-gnu", "", "64", triple); + // The rest of 10.10 is the same as previous versions. + // Ubuntu 10.04 LTS "Lucid Lynx" -- gcc-4.4.3 // Ubuntu 9.10 "Karmic Koala" -- gcc-4.4.1 // Debian 6.0 "squeeze" -- gcc-4.4.2 @@ -622,6 +632,8 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { "x86_64-linux-gnu", "32", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", "i486-linux-gnu", "", "64", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", + "arm-linux-gnueabi", "", "", triple); // Ubuntu 9.04 "Jaunty Jackalope" -- gcc-4.3.3 // Ubuntu 8.10 "Intrepid Ibex" -- gcc-4.3.2 // Debian 5.0 "lenny" -- gcc-4.3.2 @@ -646,6 +658,11 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { //===------------------------------------------------------------------===// // Redhat based distros. //===------------------------------------------------------------------===// + // Fedora 14 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.1", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.1", + "i686-redhat-linux", "", "", triple); // Fedora 13 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.4", "x86_64-redhat-linux", "32", "", triple); @@ -701,11 +718,22 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { "i586-suse-linux", "", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", "x86_64-suse-linux", "", "", triple); + + // openSUSE 11.4 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", + "i586-suse-linux", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5", + "x86_64-suse-linux", "", "", triple); + // Arch Linux 2008-06-24 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", "i686-pc-linux-gnu", "", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", "x86_64-unknown-linux-gnu", "", "", triple); + // Gentoo x86 2010.0 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.4.3/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); // Gentoo x86 2009.1 stable AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", @@ -718,26 +746,33 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", "i686-pc-linux-gnu", "", "", triple); - // Gentoo amd64 stable + + // Gentoo amd64 gcc 4.4.5 AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", "", "", triple); - - // Gentoo amd64 gcc 4.3.2 + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4", + "x86_64-pc-linux-gnu", "32", "", triple); + // Gentoo amd64 gcc 4.4.4 AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/include/g++-v4", - "x86_64-pc-linux-gnu", "", "", triple); - + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/include/g++-v4", + "x86_64-pc-linux-gnu", "32", "", triple); // Gentoo amd64 gcc 4.4.3 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.2 + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/include/g++-v4", + "x86_64-pc-linux-gnu", "", "", triple); + // Gentoo amd64 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); // Gentoo amd64 llvm-gcc trunk AddGnuCPlusPlusIncludePaths( "/usr/lib/llvm-gcc-4.2-9999/include/c++/4.2.1", "x86_64-pc-linux-gnu", "", "", triple); - + break; case llvm::Triple::FreeBSD: // FreeBSD 8.0 @@ -774,8 +809,13 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { - if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes) - AddDefaultCPlusPlusIncludePaths(triple); + if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes) { + if (!HSOpts.CXXSystemIncludes.empty()) { + for (unsigned i = 0, e = HSOpts.CXXSystemIncludes.size(); i != e; ++i) + AddPath(HSOpts.CXXSystemIncludes[i], System, true, false, false); + } else + AddDefaultCPlusPlusIncludePaths(triple); + } AddDefaultCIncludePaths(triple, HSOpts); diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 0d07192..d0111a5 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -22,8 +22,9 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/APFloat.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" using namespace clang; // Append a #define line to Buf for Macro. Macro should be of the form XXX, @@ -55,9 +56,10 @@ std::string clang::NormalizeDashIncludePath(llvm::StringRef File) { // it has not file entry. For now, workaround this by using an // absolute path if we find the file here, and otherwise letting // header search handle it. - llvm::sys::Path Path(File); - Path.makeAbsolute(); - if (!Path.exists()) + llvm::SmallString<128> Path(File); + llvm::sys::fs::make_absolute(Path); + bool exists; + if (llvm::sys::fs::exists(Path.str(), exists) || !exists) Path = File; return Lexer::Stringify(Path.str()); @@ -342,6 +344,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED"); Builder.append("class type_info;"); } + + if (LangOpts.CPlusPlus0x) { + Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", "1"); + } } if (LangOpts.Optimize) @@ -465,6 +471,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (FEOpts.ProgramAction == frontend::RunAnalysis) Builder.defineMacro("__clang_analyzer__"); + if (LangOpts.FastRelaxedMath) + Builder.defineMacro("__FAST_RELAXED_MATH__"); + // Get other target #defines. TI.getTargetDefines(LangOpts, Builder); } @@ -515,8 +524,7 @@ static void InitializeFileRemapping(Diagnostic &Diags, // Create the file entry for the file that we're mapping from. const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, - ToFile->getSize(), - 0); + ToFile->getSize(), 0); if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) << Remap->first; @@ -526,7 +534,7 @@ static void InitializeFileRemapping(Diagnostic &Diags, // Load the contents of the file we're mapping to. std::string ErrorStr; const llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); + = FileMgr.getBufferForFile(ToFile->getName(), &ErrorStr); if (!Buffer) { Diags.Report(diag::err_fe_error_opening) << Remap->second << ErrorStr; diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp new file mode 100644 index 0000000..3649c3c --- /dev/null +++ b/lib/Frontend/MultiplexConsumer.cpp @@ -0,0 +1,221 @@ +//===- MultiplexConsumer.cpp - AST Consumer for PCH Generation --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MultiplexConsumer class. It also declares and defines +// MultiplexASTDeserializationListener and MultiplexASTMutationListener, which +// are implementation details of MultiplexConsumer. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/MultiplexConsumer.h" + +#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/DeclGroup.h" +#include "clang/Serialization/ASTDeserializationListener.h" + +using namespace clang; + +namespace clang { + +// This ASTDeserializationListener forwards its notifications to a set of +// child listeners. +class MultiplexASTDeserializationListener + : public ASTDeserializationListener { +public: + // Does NOT take ownership of the elements in L. + MultiplexASTDeserializationListener( + const std::vector<ASTDeserializationListener*>& L); + virtual void ReaderInitialized(ASTReader *Reader); + virtual void IdentifierRead(serialization::IdentID ID, + IdentifierInfo *II); + 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, + MacroDefinition *MD); +private: + std::vector<ASTDeserializationListener*> Listeners; +}; + +MultiplexASTDeserializationListener::MultiplexASTDeserializationListener( + const std::vector<ASTDeserializationListener*>& L) + : Listeners(L) { +} + +void MultiplexASTDeserializationListener::ReaderInitialized( + ASTReader *Reader) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->ReaderInitialized(Reader); +} + +void MultiplexASTDeserializationListener::IdentifierRead( + serialization::IdentID ID, IdentifierInfo *II) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->IdentifierRead(ID, II); +} + +void MultiplexASTDeserializationListener::TypeRead( + serialization::TypeIdx Idx, QualType T) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->TypeRead(Idx, T); +} + +void MultiplexASTDeserializationListener::DeclRead( + serialization::DeclID ID, const Decl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->DeclRead(ID, D); +} + +void MultiplexASTDeserializationListener::SelectorRead( + serialization::SelectorID ID, Selector Sel) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->SelectorRead(ID, Sel); +} + +void MultiplexASTDeserializationListener::MacroDefinitionRead( + serialization::MacroID ID, MacroDefinition *MD) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->MacroDefinitionRead(ID, MD); +} + +// This ASTMutationListener forwards its notifications to a set of +// child listeners. +class MultiplexASTMutationListener : public ASTMutationListener { +public: + // Does NOT take ownership of the elements in L. + MultiplexASTMutationListener(const std::vector<ASTMutationListener*>& L); + virtual void CompletedTagDefinition(const TagDecl *D); + virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D); + virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D); + virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, + const ClassTemplateSpecializationDecl *D); +private: + std::vector<ASTMutationListener*> Listeners; +}; + +MultiplexASTMutationListener::MultiplexASTMutationListener( + const std::vector<ASTMutationListener*>& L) + : Listeners(L) { +} + +void MultiplexASTMutationListener::CompletedTagDefinition(const TagDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->CompletedTagDefinition(D); +} + +void MultiplexASTMutationListener::AddedVisibleDecl( + const DeclContext *DC, const Decl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->AddedVisibleDecl(DC, D); +} + +void MultiplexASTMutationListener::AddedCXXImplicitMember( + const CXXRecordDecl *RD, const Decl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->AddedCXXImplicitMember(RD, D); +} +void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( + const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->AddedCXXTemplateSpecialization(TD, D); +} + +} // end namespace clang + + +MultiplexConsumer::MultiplexConsumer(const std::vector<ASTConsumer*>& C) + : Consumers(C), MutationListener(0), DeserializationListener(0) { + // Collect the mutation listeners and deserialization listeners of all + // children, and create a multiplex listener each if so. + std::vector<ASTMutationListener*> mutationListeners; + std::vector<ASTDeserializationListener*> serializationListeners; + for (size_t i = 0, e = Consumers.size(); i != e; ++i) { + ASTMutationListener* mutationListener = + Consumers[i]->GetASTMutationListener(); + if (mutationListener) + mutationListeners.push_back(mutationListener); + ASTDeserializationListener* serializationListener = + Consumers[i]->GetASTDeserializationListener(); + if (serializationListener) + serializationListeners.push_back(serializationListener); + } + if (mutationListeners.size()) { + MutationListener.reset(new MultiplexASTMutationListener(mutationListeners)); + } + if (serializationListeners.size()) { + DeserializationListener.reset( + new MultiplexASTDeserializationListener(serializationListeners)); + } +} + +MultiplexConsumer::~MultiplexConsumer() { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + delete Consumers[i]; +} + +void MultiplexConsumer::Initialize(ASTContext &Context) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->Initialize(Context); +} + +void MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleTopLevelDecl(D); +} + +void MultiplexConsumer::HandleInterestingDecl(DeclGroupRef D) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleInterestingDecl(D); +} + +void MultiplexConsumer::HandleTranslationUnit(ASTContext &Ctx) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleTranslationUnit(Ctx); +} + +void MultiplexConsumer::HandleTagDeclDefinition(TagDecl *D) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleTagDeclDefinition(D); +} + +void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->CompleteTentativeDefinition(D); +} + +void MultiplexConsumer::HandleVTable( + CXXRecordDecl *RD, bool DefinitionRequired) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleVTable(RD, DefinitionRequired); +} + +ASTMutationListener *MultiplexConsumer::GetASTMutationListener() { + return MutationListener.get(); +} + +ASTDeserializationListener *MultiplexConsumer::GetASTDeserializationListener() { + return DeserializationListener.get(); +} + +void MultiplexConsumer::PrintStats() { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->PrintStats(); +} + +void MultiplexConsumer::InitializeSema(Sema &S) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumers[i])) + SC->InitializeSema(S); +} + +void MultiplexConsumer::ForgetSema() { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumers[i])) + SC->ForgetSema(); +} diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index cfaf8a2..922d743 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -86,9 +86,6 @@ public: private: unsigned CurLine; - /// The current include nesting level, used by header include dumping (-H). - unsigned CurrentIncludeDepth; - bool EmittedTokensOnThisLine; bool EmittedMacroOnThisLine; SrcMgr::CharacteristicKind FileType; @@ -96,22 +93,19 @@ private: bool Initialized; bool DisableLineMarkers; bool DumpDefines; - bool DumpHeaderIncludes; bool UseLineDirective; - bool HasProcessedPredefines; public: PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os, - bool lineMarkers, bool defines, bool headers) + bool lineMarkers, bool defines) : PP(pp), SM(PP.getSourceManager()), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers), - DumpDefines(defines), DumpHeaderIncludes(headers) { - CurLine = CurrentIncludeDepth = 0; + DumpDefines(defines) { + CurLine = 0; CurFilename += "<uninit>"; EmittedTokensOnThisLine = false; EmittedMacroOnThisLine = false; FileType = SrcMgr::C_User; Initialized = false; - HasProcessedPredefines = false; // If we're in microsoft mode, use normal #line instead of line markers. UseLineDirective = PP.getLangOptions().Microsoft; @@ -120,6 +114,8 @@ public: void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; } bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; } + bool StartNewLineIfNeeded(); + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType); virtual void Ident(SourceLocation Loc, const std::string &str); @@ -129,7 +125,10 @@ public: bool HandleFirstTokOnLine(Token &Tok); bool MoveToLine(SourceLocation Loc) { - return MoveToLine(SM.getPresumedLoc(Loc).getLine()); + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + if (PLoc.isInvalid()) + return false; + return MoveToLine(PLoc.getLine()); } bool MoveToLine(unsigned LineNo); @@ -138,15 +137,14 @@ public: return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok); } void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0); - + bool LineMarkersAreDisabled() const { return DisableLineMarkers; } void HandleNewlinesInToken(const char *TokStr, unsigned Len); /// MacroDefined - This hook is called whenever a macro definition is seen. - void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI); + void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI); /// MacroUndefined - This hook is called whenever a macro #undef is seen. - void MacroUndefined(SourceLocation Loc, const IdentifierInfo *II, - const MacroInfo *MI); + void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI); }; } // end anonymous namespace @@ -162,11 +160,11 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo, // Emit #line directives or GNU line markers depending on what mode we're in. if (UseLineDirective) { OS << "#line" << ' ' << LineNo << ' ' << '"'; - OS.write(&CurFilename[0], CurFilename.size()); + OS.write(CurFilename.data(), CurFilename.size()); OS << '"'; } else { OS << '#' << ' ' << LineNo << ' ' << '"'; - OS.write(&CurFilename[0], CurFilename.size()); + OS.write(CurFilename.data(), CurFilename.size()); OS << '"'; if (ExtraLen) @@ -213,6 +211,17 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) { return true; } +bool PrintPPOutputPPCallbacks::StartNewLineIfNeeded() { + if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) { + OS << '\n'; + EmittedTokensOnThisLine = false; + EmittedMacroOnThisLine = false; + ++CurLine; + return true; + } + + return false; +} /// FileChanged - Whenever the preprocessor enters or exits a #include file /// it invokes this handler. Update our conception of the current source @@ -225,10 +234,13 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, SourceManager &SourceMgr = SM; PresumedLoc UserLoc = SourceMgr.getPresumedLoc(Loc); + if (UserLoc.isInvalid()) + return; + unsigned NewLine = UserLoc.getLine(); if (Reason == PPCallbacks::EnterFile) { - SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc(); + SourceLocation IncludeLoc = UserLoc.getIncludeLoc(); if (IncludeLoc.isValid()) MoveToLine(IncludeLoc); } else if (Reason == PPCallbacks::SystemHeaderPragma) { @@ -238,19 +250,6 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, // directive and emits a bunch of spaces that aren't needed. Emulate this // strange behavior. } - - // Adjust the current include depth. - if (Reason == PPCallbacks::EnterFile) { - ++CurrentIncludeDepth; - } else { - if (CurrentIncludeDepth) - --CurrentIncludeDepth; - - // We track when we are done with the predefines by watching for the first - // place where we drop back to a nesting depth of 0. - if (CurrentIncludeDepth == 0 && !HasProcessedPredefines) - HasProcessedPredefines = true; - } CurLine = NewLine; @@ -259,18 +258,6 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, Lexer::Stringify(CurFilename); FileType = NewFileType; - // Dump the header include information, if enabled and we are past the - // predefines buffer. - if (DumpHeaderIncludes && HasProcessedPredefines && - Reason == PPCallbacks::EnterFile) { - llvm::SmallString<256> Msg; - llvm::raw_svector_ostream OS(Msg); - for (unsigned i = 0; i != CurrentIncludeDepth; ++i) - OS << '.'; - OS << ' ' << CurFilename << '\n'; - llvm::errs() << OS.str(); - } - if (DisableLineMarkers) return; if (!Initialized) { @@ -303,7 +290,7 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) { } /// MacroDefined - This hook is called whenever a macro definition is seen. -void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II, +void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { // Only print out macro definitions in -dD mode. if (!DumpDefines || @@ -311,18 +298,17 @@ void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II, MI->isBuiltinMacro()) return; MoveToLine(MI->getDefinitionLoc()); - PrintMacroDefinition(*II, *MI, PP, OS); + PrintMacroDefinition(*MacroNameTok.getIdentifierInfo(), *MI, PP, OS); EmittedMacroOnThisLine = true; } -void PrintPPOutputPPCallbacks::MacroUndefined(SourceLocation Loc, - const IdentifierInfo *II, +void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) { // Only print out macro definitions in -dD mode. if (!DumpDefines) return; - MoveToLine(Loc); - OS << "#undef " << II->getName(); + MoveToLine(MacroNameTok.getLocation()); + OS << "#undef " << MacroNameTok.getIdentifierInfo()->getName(); EmittedMacroOnThisLine = true; } @@ -437,12 +423,14 @@ struct UnknownPragmaHandler : public PragmaHandler { UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks) : Prefix(prefix), Callbacks(callbacks) {} - virtual void HandlePragma(Preprocessor &PP, Token &PragmaTok) { + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &PragmaTok) { // Figure out what line we went to and insert the appropriate number of // newline characters. + Callbacks->StartNewLineIfNeeded(); Callbacks->MoveToLine(PragmaTok.getLocation()); Callbacks->OS.write(Prefix, strlen(Prefix)); - + Callbacks->SetEmittedTokensOnThisLine(); // Read and print all of the pragma tokens. while (PragmaTok.isNot(tok::eom)) { if (PragmaTok.hasLeadingSpace()) @@ -451,7 +439,7 @@ struct UnknownPragmaHandler : public PragmaHandler { Callbacks->OS.write(&TokSpell[0], TokSpell.size()); PP.LexUnexpandedToken(PragmaTok); } - Callbacks->OS << '\n'; + Callbacks->StartNewLineIfNeeded(); } }; } // end anonymous namespace @@ -561,10 +549,11 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers, - Opts.ShowMacros, Opts.ShowHeaderIncludes); + Opts.ShowMacros); PP.AddPragmaHandler(new UnknownPragmaHandler("#pragma", Callbacks)); - PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC", - Callbacks)); + PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",Callbacks)); + PP.AddPragmaHandler("clang", + new UnknownPragmaHandler("#pragma clang", Callbacks)); PP.addPPCallbacks(Callbacks); @@ -576,13 +565,20 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, // start. const SourceManager &SourceMgr = PP.getSourceManager(); Token Tok; - do PP.Lex(Tok); - while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() && - !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(), - "<built-in>")); + do { + PP.Lex(Tok); + if (Tok.is(tok::eof) || !Tok.getLocation().isFileID()) + break; + + PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); + if (PLoc.isInvalid()) + break; + + if (strcmp(PLoc.getFilename(), "<built-in>")) + break; + } while (true); // Read all the preprocessed tokens, printing them out to the stream. PrintPreprocessedTokens(PP, Tok, Callbacks, *OS); *OS << '\n'; } - diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp index b660734..c113cc1 100644 --- a/lib/Frontend/StmtXML.cpp +++ b/lib/Frontend/StmtXML.cpp @@ -61,8 +61,7 @@ namespace { Doc.PrintDecl(*DI); } } else { - for (Stmt::child_iterator i = S->child_begin(), e = S->child_end(); - i != e; ++i) + for (Stmt::child_range i = S->children(); i; ++i) DumpSubTree(*i); } Doc.toParent(); @@ -133,7 +132,6 @@ namespace { void VisitBinaryOperator(BinaryOperator *Node); void VisitCompoundAssignOperator(CompoundAssignOperator *Node); void VisitAddrLabelExpr(AddrLabelExpr *Node); - void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node); // C++ void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); @@ -150,7 +148,6 @@ namespace { void VisitObjCImplicitSetterGetterRefExpr( ObjCImplicitSetterGetterRefExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); - void VisitObjCSuperExpr(ObjCSuperExpr *Node); #endif }; } @@ -357,12 +354,6 @@ void StmtXML::VisitAddrLabelExpr(AddrLabelExpr *Node) { Doc.addAttribute("name", Node->getLabel()->getName()); } -void StmtXML::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { - DumpExpr(Node); - DumpTypeExpr(Node->getArgType1()); - DumpTypeExpr(Node->getArgType2()); -} - //===----------------------------------------------------------------------===// // C++ Expressions //===----------------------------------------------------------------------===// @@ -428,11 +419,6 @@ void StmtXML::VisitObjCImplicitSetterGetterRefExpr( Doc.addAttribute("Setter", Setter ? Setter->getSelector().getAsString().c_str() : "(null)"); } -void StmtXML::VisitObjCSuperExpr(ObjCSuperExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("super", "1"); -} - void StmtXML::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { DumpExpr(Node); Doc.addAttribute("kind", Node->getDecl()->getDeclKindName()); diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp index fdf2ec8..069c86d 100644 --- a/lib/Frontend/TextDiagnosticBuffer.cpp +++ b/lib/Frontend/TextDiagnosticBuffer.cpp @@ -20,6 +20,9 @@ using namespace clang; /// void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info) { + // Default implementation (Warnings/errors count). + DiagnosticClient::HandleDiagnostic(Level, Info); + llvm::SmallString<100> Buf; Info.FormatDiagnostic(Buf); switch (Level) { diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 1e453a0..04c6a68 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" @@ -57,7 +58,9 @@ PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { if (Loc.isInvalid()) return; PresumedLoc PLoc = SM.getPresumedLoc(Loc); - + if (PLoc.isInvalid()) + return; + // Print out the other include frames first. PrintIncludeStack(PLoc.getIncludeLoc(), SM); @@ -137,8 +140,9 @@ void TextDiagnosticPrinter::HighlightRange(const CharSourceRange &R, (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. + // 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??"); } @@ -328,7 +332,9 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, if (!Suppressed) { // Get the pretty name, according to #line directives etc. PresumedLoc PLoc = SM.getPresumedLoc(Loc); - + if (PLoc.isInvalid()) + return; + // If this diagnostic is not in the main file, print out the // "included from" lines. if (LastWarningLoc != PLoc.getIncludeLoc()) { @@ -567,6 +573,10 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, // 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) @@ -756,6 +766,9 @@ static bool PrintWordWrapped(llvm::raw_ostream &OS, void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info) { + // Default implementation (Warnings/errors count). + DiagnosticClient::HandleDiagnostic(Level, Info); + // Keeps track of the the starting position of the location // information (e.g., "foo.c:10:4:") that precedes the error // message. We use this information to determine how long the @@ -768,77 +781,96 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, // If the location is specified, print out a file/line/col and include trace // if enabled. if (Info.getLocation().isValid()) { - const SourceManager &SM = Info.getLocation().getManager(); + const SourceManager &SM = Info.getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); - 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(LastWarningLoc, SM); - StartOfLocationInfo = OS.tell(); - } + 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(); - // Compute the column number. - if (DiagOpts->ShowLocation) { - if (DiagOpts->ShowColors) - OS.changeColor(savedColor, true); - - // Emit a Visual Studio compatible line number syntax. - if (LangOpts && LangOpts->Microsoft) { - OS << PLoc.getFilename() << '(' << LineNo << ')'; - OS << " : "; - } else { - OS << PLoc.getFilename() << ':' << LineNo << ':'; - if (DiagOpts->ShowColumn) - if (unsigned ColNo = PLoc.getColumn()) - OS << ColNo << ':'; + // First, if this diagnostic is not in the main file, print out the + // "included from" lines. + if (LastWarningLoc != PLoc.getIncludeLoc()) { + LastWarningLoc = PLoc.getIncludeLoc(); + PrintIncludeStack(LastWarningLoc, SM); + StartOfLocationInfo = OS.tell(); } - 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 << ':'; + // Compute the column number. + if (DiagOpts->ShowLocation && PLoc.isValid()) { + if (DiagOpts->ShowColors) + OS.changeColor(savedColor, true); + + // Emit a Visual Studio compatible line number syntax. + if (LangOpts && LangOpts->Microsoft) { + OS << PLoc.getFilename() << '(' << LineNo << ')'; + OS << " : "; + } else { + OS << PLoc.getFilename() << ':' << LineNo << ':'; + if (DiagOpts->ShowColumn) + if (unsigned ColNo = PLoc.getColumn()) + OS << ColNo << ':'; + } + 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) @@ -873,7 +905,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, std::string OptionName; if (DiagOpts->ShowOptionNames) { - if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) { + if (const char * + Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID())) { OptionName = "-W"; OptionName += Opt; } else if (Info.getID() == diag::fatal_too_many_errors) { @@ -882,7 +915,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, // If the diagnostic is an extension diagnostic and not enabled by default // then it must have been turned on with -pedantic. bool EnabledByDefault; - if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) && + if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(), + EnabledByDefault) && !EnabledByDefault) OptionName = "-pedantic"; } @@ -891,7 +925,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, // If the user wants to see category information, include it too. unsigned DiagCategory = 0; if (DiagOpts->ShowCategories) - DiagCategory = Diagnostic::getCategoryNumberForDiag(Info.getID()); + DiagCategory = DiagnosticIDs::getCategoryNumberForDiag(Info.getID()); // If there is any categorization information, include it. if (!OptionName.empty() || DiagCategory != 0) { @@ -909,7 +943,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, OutStr += llvm::utostr(DiagCategory); else { assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value"); - OutStr += Diagnostic::getCategoryNameFromID(DiagCategory); + OutStr += DiagnosticIDs::getCategoryNameFromID(DiagCategory); } } @@ -951,7 +985,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || Info.getNumFixItHints())) { // Cache the LastLoc, it allows us to omit duplicate source/caret spewage. - LastLoc = Info.getLocation(); + LastLoc = FullSourceLoc(Info.getLocation(), Info.getSourceManager()); LastCaretDiagnosticWasNote = (Level == Diagnostic::Note); // Get the ranges into a local array we can hack on. diff --git a/lib/Frontend/TypeXML.cpp b/lib/Frontend/TypeXML.cpp index be9db42..a8c8f75 100644 --- a/lib/Frontend/TypeXML.cpp +++ b/lib/Frontend/TypeXML.cpp @@ -29,7 +29,7 @@ public: TypeWriter(DocumentXML& doc) : Doc(doc) {} #define NODE_XML( CLASS, NAME ) \ - void Visit##CLASS(CLASS* T) { \ + void Visit##CLASS(const CLASS* T) { \ Doc.addSubNode(NAME); #define ID_ATTRIBUTE_XML // done by the Document class itself @@ -82,7 +82,7 @@ public: TypeAdder(DocumentXML& doc) : Doc(doc) {} #define NODE_XML( CLASS, NAME ) \ - void Visit##CLASS(CLASS* T) \ + void Visit##CLASS(const CLASS* T) \ { #define ID_ATTRIBUTE_XML @@ -101,7 +101,7 @@ public: //--------------------------------------------------------- void DocumentXML::addParentTypes(const Type* pType) { - TypeAdder(*this).Visit(const_cast<Type*>(pType)); + TypeAdder(*this).Visit(pType); } //--------------------------------------------------------- diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp index 31eb28f..51b351f 100644 --- a/lib/Frontend/VerifyDiagnosticsClient.cpp +++ b/lib/Frontend/VerifyDiagnosticsClient.cpp @@ -23,7 +23,7 @@ using namespace clang; VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags, DiagnosticClient *_Primary) : Diags(_Diags), PrimaryClient(_Primary), - Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), NumErrors(0) { + Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) { } VerifyDiagnosticsClient::~VerifyDiagnosticsClient() { @@ -57,14 +57,6 @@ void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel, Buffer->HandleDiagnostic(DiagLevel, Info); } -// FIXME: It would be nice to just get this from the primary diagnostic client -// or something. -bool VerifyDiagnosticsClient::HadErrors() { - CheckDiagnostics(); - - return NumErrors != 0; -} - //===----------------------------------------------------------------------===// // Checking diagnostics implementation. //===----------------------------------------------------------------------===// |