diff options
Diffstat (limited to 'lib/Frontend')
-rw-r--r-- | lib/Frontend/ASTConsumers.cpp | 99 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 224 | ||||
-rw-r--r-- | lib/Frontend/CMakeLists.txt | 45 | ||||
-rw-r--r-- | lib/Frontend/CompilerInstance.cpp | 23 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 326 | ||||
-rw-r--r-- | lib/Frontend/CreateInvocationFromCommandLine.cpp | 8 | ||||
-rw-r--r-- | lib/Frontend/DiagnosticRenderer.cpp | 127 | ||||
-rw-r--r-- | lib/Frontend/FrontendAction.cpp | 62 | ||||
-rw-r--r-- | lib/Frontend/FrontendActions.cpp | 11 | ||||
-rw-r--r-- | lib/Frontend/InitHeaderSearch.cpp | 15 | ||||
-rw-r--r-- | lib/Frontend/InitPreprocessor.cpp | 72 | ||||
-rw-r--r-- | lib/Frontend/LayoutOverrideSource.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/PrintPreprocessedOutput.cpp | 66 | ||||
-rw-r--r-- | lib/Frontend/SerializedDiagnosticPrinter.cpp | 40 | ||||
-rw-r--r-- | lib/Frontend/TextDiagnostic.cpp | 217 | ||||
-rw-r--r-- | lib/Frontend/TextDiagnosticPrinter.cpp | 30 | ||||
-rw-r--r-- | lib/Frontend/VerifyDiagnosticConsumer.cpp | 471 | ||||
-rw-r--r-- | lib/Frontend/Warnings.cpp | 14 |
18 files changed, 1150 insertions, 701 deletions
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 390ae09..bb1a4e6 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -12,47 +12,116 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTConsumers.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" -#include "clang/Basic/FileManager.h" #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/RecordLayout.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "llvm/Module.h" -#include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Timer.h" using namespace clang; //===----------------------------------------------------------------------===// /// ASTPrinter - Pretty-printer and dumper of ASTs namespace { - class ASTPrinter : public ASTConsumer { + class ASTPrinter : public ASTConsumer, + public RecursiveASTVisitor<ASTPrinter> { + typedef RecursiveASTVisitor<ASTPrinter> base; + + public: + ASTPrinter(raw_ostream *Out = NULL, bool Dump = false, + StringRef FilterString = "") + : Out(Out ? *Out : llvm::outs()), Dump(Dump), + FilterString(FilterString) {} + + virtual void HandleTranslationUnit(ASTContext &Context) { + TranslationUnitDecl *D = Context.getTranslationUnitDecl(); + + if (FilterString.empty()) { + if (Dump) + D->dump(Out); + else + D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true); + return; + } + + TraverseDecl(D); + } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool TraverseDecl(Decl *D) { + if (filterMatches(D)) { + Out.changeColor(llvm::raw_ostream::BLUE) << + (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n"; + Out.resetColor(); + if (Dump) + D->dump(Out); + else + D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true); + // Don't traverse child nodes to avoid output duplication. + return true; + } + return base::TraverseDecl(D); + } + + private: + std::string getName(Decl *D) { + if (isa<NamedDecl>(D)) + return cast<NamedDecl>(D)->getQualifiedNameAsString(); + return ""; + } + bool filterMatches(Decl *D) { + return getName(D).find(FilterString) != std::string::npos; + } + raw_ostream &Out; bool Dump; + std::string FilterString; + }; + + class ASTDeclNodeLister : public ASTConsumer, + public RecursiveASTVisitor<ASTDeclNodeLister> { + typedef RecursiveASTVisitor<ASTPrinter> base; public: - ASTPrinter(raw_ostream* o = NULL, bool Dump = false) - : Out(o? *o : llvm::outs()), Dump(Dump) { } + ASTDeclNodeLister(raw_ostream *Out = NULL) + : Out(Out ? *Out : llvm::outs()) {} virtual void HandleTranslationUnit(ASTContext &Context) { - PrintingPolicy Policy = Context.getPrintingPolicy(); - Policy.Dump = Dump; - Context.getTranslationUnitDecl()->print(Out, Policy, /*Indentation=*/0, - /*PrintInstantiation=*/true); + TraverseDecl(Context.getTranslationUnitDecl()); } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + virtual bool VisitNamedDecl(NamedDecl *D) { + Out << D->getQualifiedNameAsString() << "\n"; + return true; + } + + private: + raw_ostream &Out; }; } // end anonymous namespace -ASTConsumer *clang::CreateASTPrinter(raw_ostream* out) { - return new ASTPrinter(out); +ASTConsumer *clang::CreateASTPrinter(raw_ostream *Out, + StringRef FilterString) { + return new ASTPrinter(Out, /*Dump=*/ false, FilterString); +} + +ASTConsumer *clang::CreateASTDumper(StringRef FilterString) { + return new ASTPrinter(0, /*Dump=*/ true, FilterString); } -ASTConsumer *clang::CreateASTDumper() { - return new ASTPrinter(0, true); +ASTConsumer *clang::CreateASTDeclNodeLister() { + return new ASTDeclNodeLister(0); } //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 7aa9603..42a6772 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -17,12 +17,6 @@ #include "clang/AST/DeclVisitor.h" #include "clang/AST/TypeOrdering.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/Job.h" -#include "clang/Driver/ArgList.h" -#include "clang/Driver/Options.h" -#include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -122,7 +116,8 @@ static OnDiskDataMap &getOnDiskDataMap() { } static void cleanupOnDiskMapAtExit(void) { - // No mutex required here since we are leaving the program. + // Use the mutex because there can be an alive thread destroying an ASTUnit. + llvm::MutexGuard Guard(getOnDiskMutex()); OnDiskDataMap &M = getOnDiskDataMap(); for (OnDiskDataMap::iterator I = M.begin(), E = M.end(); I != E; ++I) { // We don't worry about freeing the memory associated with OnDiskDataMap. @@ -220,6 +215,7 @@ ASTUnit::ASTUnit(bool _MainFileIsAST) PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0), NumWarningsInPreamble(0), ShouldCacheCodeCompletionResults(false), + IncludeBriefCommentsInCodeCompletion(false), UserFilesAreVolatile(false), CompletionCacheTopLevelHashValue(0), PreambleTopLevelHashValue(0), CurrentTopLevelHashValue(0), @@ -275,43 +271,43 @@ static unsigned getDeclShowContexts(NamedDecl *ND, if (!ND) return 0; - unsigned Contexts = 0; + uint64_t Contexts = 0; if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND) || isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND)) { // Types can appear in these contexts. if (LangOpts.CPlusPlus || !isa<TagDecl>(ND)) - Contexts |= (1 << (CodeCompletionContext::CCC_TopLevel - 1)) - | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) - | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) - | (1 << (CodeCompletionContext::CCC_Statement - 1)) - | (1 << (CodeCompletionContext::CCC_Type - 1)) - | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1)); + Contexts |= (1LL << CodeCompletionContext::CCC_TopLevel) + | (1LL << CodeCompletionContext::CCC_ObjCIvarList) + | (1LL << CodeCompletionContext::CCC_ClassStructUnion) + | (1LL << CodeCompletionContext::CCC_Statement) + | (1LL << CodeCompletionContext::CCC_Type) + | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression); // In C++, types can appear in expressions contexts (for functional casts). if (LangOpts.CPlusPlus) - Contexts |= (1 << (CodeCompletionContext::CCC_Expression - 1)); + Contexts |= (1LL << CodeCompletionContext::CCC_Expression); // In Objective-C, message sends can send interfaces. In Objective-C++, // all types are available due to functional casts. if (LangOpts.CPlusPlus || isa<ObjCInterfaceDecl>(ND)) - Contexts |= (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)); + Contexts |= (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver); // In Objective-C, you can only be a subclass of another Objective-C class if (isa<ObjCInterfaceDecl>(ND)) - Contexts |= (1 << (CodeCompletionContext::CCC_ObjCInterfaceName - 1)); + Contexts |= (1LL << CodeCompletionContext::CCC_ObjCInterfaceName); // Deal with tag names. if (isa<EnumDecl>(ND)) { - Contexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1)); + Contexts |= (1LL << CodeCompletionContext::CCC_EnumTag); // Part of the nested-name-specifier in C++0x. if (LangOpts.CPlusPlus0x) IsNestedNameSpecifier = true; } else if (RecordDecl *Record = dyn_cast<RecordDecl>(ND)) { if (Record->isUnion()) - Contexts |= (1 << (CodeCompletionContext::CCC_UnionTag - 1)); + Contexts |= (1LL << CodeCompletionContext::CCC_UnionTag); else - Contexts |= (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)); + Contexts |= (1LL << CodeCompletionContext::CCC_ClassOrStructTag); if (LangOpts.CPlusPlus) IsNestedNameSpecifier = true; @@ -319,16 +315,16 @@ static unsigned getDeclShowContexts(NamedDecl *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)); + Contexts = (1LL << CodeCompletionContext::CCC_Statement) + | (1LL << CodeCompletionContext::CCC_Expression) + | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression) + | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver); } else if (isa<ObjCProtocolDecl>(ND)) { - Contexts = (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1)); + Contexts = (1LL << CodeCompletionContext::CCC_ObjCProtocolName); } else if (isa<ObjCCategoryDecl>(ND)) { - Contexts = (1 << (CodeCompletionContext::CCC_ObjCCategoryName - 1)); + Contexts = (1LL << CodeCompletionContext::CCC_ObjCCategoryName); } else if (isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) { - Contexts = (1 << (CodeCompletionContext::CCC_Namespace - 1)); + Contexts = (1LL << CodeCompletionContext::CCC_Namespace); // Part of the nested-name-specifier. IsNestedNameSpecifier = true; @@ -364,7 +360,8 @@ void ASTUnit::CacheCodeCompletionResults() { CachedCodeCompletionResult CachedResult; CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema, *CachedCompletionAllocator, - getCodeCompletionTUInfo()); + getCodeCompletionTUInfo(), + IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration, Ctx->getLangOpts(), IsNestedNameSpecifier); @@ -402,23 +399,23 @@ void ASTUnit::CacheCodeCompletionResults() { if (TheSema->Context.getLangOpts().CPlusPlus && IsNestedNameSpecifier && !Results[I].StartsNestedNameSpecifier) { // The contexts in which a nested-name-specifier can appear in C++. - unsigned NNSContexts - = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) - | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) - | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) - | (1 << (CodeCompletionContext::CCC_Statement - 1)) - | (1 << (CodeCompletionContext::CCC_Expression - 1)) - | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) - | (1 << (CodeCompletionContext::CCC_EnumTag - 1)) - | (1 << (CodeCompletionContext::CCC_UnionTag - 1)) - | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)) - | (1 << (CodeCompletionContext::CCC_Type - 1)) - | (1 << (CodeCompletionContext::CCC_PotentiallyQualifiedName - 1)) - | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1)); + uint64_t NNSContexts + = (1LL << CodeCompletionContext::CCC_TopLevel) + | (1LL << CodeCompletionContext::CCC_ObjCIvarList) + | (1LL << CodeCompletionContext::CCC_ClassStructUnion) + | (1LL << CodeCompletionContext::CCC_Statement) + | (1LL << CodeCompletionContext::CCC_Expression) + | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver) + | (1LL << CodeCompletionContext::CCC_EnumTag) + | (1LL << CodeCompletionContext::CCC_UnionTag) + | (1LL << CodeCompletionContext::CCC_ClassOrStructTag) + | (1LL << CodeCompletionContext::CCC_Type) + | (1LL << CodeCompletionContext::CCC_PotentiallyQualifiedName) + | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression); if (isa<NamespaceDecl>(Results[I].Declaration) || isa<NamespaceAliasDecl>(Results[I].Declaration)) - NNSContexts |= (1 << (CodeCompletionContext::CCC_Namespace - 1)); + NNSContexts |= (1LL << CodeCompletionContext::CCC_Namespace); if (unsigned RemainingContexts = NNSContexts & ~CachedResult.ShowInContexts) { @@ -429,7 +426,8 @@ void ASTUnit::CacheCodeCompletionResults() { CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema, *CachedCompletionAllocator, - getCodeCompletionTUInfo()); + getCodeCompletionTUInfo(), + IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts = RemainingContexts; CachedResult.Priority = CCP_NestedNameSpecifier; CachedResult.TypeClass = STC_Void; @@ -451,20 +449,21 @@ void ASTUnit::CacheCodeCompletionResults() { CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema, *CachedCompletionAllocator, - getCodeCompletionTUInfo()); + getCodeCompletionTUInfo(), + IncludeBriefCommentsInCodeCompletion); CachedResult.ShowInContexts - = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) - | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1)) - | (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1)) - | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) - | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) - | (1 << (CodeCompletionContext::CCC_Statement - 1)) - | (1 << (CodeCompletionContext::CCC_Expression - 1)) - | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) - | (1 << (CodeCompletionContext::CCC_MacroNameUse - 1)) - | (1 << (CodeCompletionContext::CCC_PreprocessorExpression - 1)) - | (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1)) - | (1 << (CodeCompletionContext::CCC_OtherWithMacros - 1)); + = (1LL << CodeCompletionContext::CCC_TopLevel) + | (1LL << CodeCompletionContext::CCC_ObjCInterface) + | (1LL << CodeCompletionContext::CCC_ObjCImplementation) + | (1LL << CodeCompletionContext::CCC_ObjCIvarList) + | (1LL << CodeCompletionContext::CCC_ClassStructUnion) + | (1LL << CodeCompletionContext::CCC_Statement) + | (1LL << CodeCompletionContext::CCC_Expression) + | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver) + | (1LL << CodeCompletionContext::CCC_MacroNameUse) + | (1LL << CodeCompletionContext::CCC_PreprocessorExpression) + | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression) + | (1LL << CodeCompletionContext::CCC_OtherWithMacros); CachedResult.Priority = Results[I].Priority; CachedResult.Kind = Results[I].CursorKind; @@ -659,7 +658,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, bool CaptureDiagnostics, - bool AllowPCHWithCompilerErrors) { + bool AllowPCHWithCompilerErrors, + bool UserFilesAreVolatile) { OwningPtr<ASTUnit> AST(new ASTUnit(true)); // Recover resources if we crash before exiting this method. @@ -675,8 +675,10 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, AST->CaptureDiagnostics = CaptureDiagnostics; AST->Diagnostics = Diags; AST->FileMgr = new FileManager(FileSystemOpts); + AST->UserFilesAreVolatile = UserFilesAreVolatile; AST->SourceMgr = new SourceManager(AST->getDiagnostics(), - AST->getFileManager()); + AST->getFileManager(), + UserFilesAreVolatile); AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(), AST->getDiagnostics(), AST->ASTFileLangOpts, @@ -1078,7 +1080,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { LangOpts = &Clang->getLangOpts(); FileSystemOpts = Clang->getFileSystemOpts(); FileMgr = new FileManager(FileSystemOpts); - SourceMgr = new SourceManager(getDiagnostics(), *FileMgr); + SourceMgr = new SourceManager(getDiagnostics(), *FileMgr, + UserFilesAreVolatile); TheSema.reset(); Ctx = 0; PP = 0; @@ -1139,7 +1142,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { StoredDiagnostics); } - Act->Execute(); + if (!Act->Execute()) + goto error; transferASTDataFromCompilerInstance(*Clang); @@ -1665,7 +1669,8 @@ StringRef ASTUnit::getMainFileName() const { ASTUnit *ASTUnit::create(CompilerInvocation *CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, - bool CaptureDiagnostics) { + bool CaptureDiagnostics, + bool UserFilesAreVolatile) { OwningPtr<ASTUnit> AST; AST.reset(new ASTUnit(false)); ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics); @@ -1673,7 +1678,9 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI, AST->Invocation = CI; AST->FileSystemOpts = CI->getFileSystemOpts(); AST->FileMgr = new FileManager(AST->FileSystemOpts); - AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr); + AST->UserFilesAreVolatile = UserFilesAreVolatile; + AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr, + UserFilesAreVolatile); return AST.take(); } @@ -1688,6 +1695,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, bool CaptureDiagnostics, bool PrecompilePreamble, bool CacheCodeCompletionResults, + bool IncludeBriefCommentsInCodeCompletion, + bool UserFilesAreVolatile, OwningPtr<ASTUnit> *ErrAST) { assert(CI && "A CompilerInvocation is required"); @@ -1695,7 +1704,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, ASTUnit *AST = Unit; if (!AST) { // Create the AST unit. - OwnAST.reset(create(CI, Diags, CaptureDiagnostics)); + OwnAST.reset(create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile)); AST = OwnAST.get(); } @@ -1709,6 +1718,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, AST->PreambleRebuildCounter = 2; AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; + AST->IncludeBriefCommentsInCodeCompletion + = IncludeBriefCommentsInCodeCompletion; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> @@ -1801,7 +1812,13 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, AST->getCurrentTopLevelHashValue())); Clang->setASTConsumer(new MultiplexConsumer(Consumers)); } - Act->Execute(); + if (!Act->Execute()) { + AST->transferASTDataFromCompilerInstance(*Clang); + if (OwnAST && ErrAST) + ErrAST->swap(OwnAST); + + return 0; + } // Steal the created target, context, and preprocessor. AST->transferASTDataFromCompilerInstance(*Clang); @@ -1849,7 +1866,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, bool CaptureDiagnostics, bool PrecompilePreamble, TranslationUnitKind TUKind, - bool CacheCodeCompletionResults) { + bool CacheCodeCompletionResults, + bool IncludeBriefCommentsInCodeCompletion, + bool UserFilesAreVolatile) { // Create the AST unit. OwningPtr<ASTUnit> AST; AST.reset(new ASTUnit(false)); @@ -1859,7 +1878,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, AST->CaptureDiagnostics = CaptureDiagnostics; AST->TUKind = TUKind; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; + AST->IncludeBriefCommentsInCodeCompletion + = IncludeBriefCommentsInCodeCompletion; AST->Invocation = CI; + AST->UserFilesAreVolatile = UserFilesAreVolatile; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> @@ -1883,8 +1905,10 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, bool PrecompilePreamble, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, + bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies, + bool UserFilesAreVolatile, OwningPtr<ASTUnit> *ErrAST) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object @@ -1942,6 +1966,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, AST->CaptureDiagnostics = CaptureDiagnostics; AST->TUKind = TUKind; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; + AST->IncludeBriefCommentsInCodeCompletion + = IncludeBriefCommentsInCodeCompletion; + AST->UserFilesAreVolatile = UserFilesAreVolatile; AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); AST->StoredDiagnostics.swap(StoredDiagnostics); AST->Invocation = CI; @@ -2034,38 +2061,37 @@ namespace { /// results from an ASTUnit with the code-completion results provided to it, /// then passes the result on to class AugmentedCodeCompleteConsumer : public CodeCompleteConsumer { - unsigned long long NormalContexts; + uint64_t NormalContexts; ASTUnit &AST; CodeCompleteConsumer &Next; public: AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next, - bool IncludeMacros, bool IncludeCodePatterns, - bool IncludeGlobals) - : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals, - Next.isOutputBinary()), AST(AST), Next(Next) + const CodeCompleteOptions &CodeCompleteOpts) + : CodeCompleteConsumer(CodeCompleteOpts, Next.isOutputBinary()), + AST(AST), Next(Next) { // Compute the set of contexts in which we will look when we don't have // any information about the specific context. NormalContexts - = (1LL << (CodeCompletionContext::CCC_TopLevel - 1)) - | (1LL << (CodeCompletionContext::CCC_ObjCInterface - 1)) - | (1LL << (CodeCompletionContext::CCC_ObjCImplementation - 1)) - | (1LL << (CodeCompletionContext::CCC_ObjCIvarList - 1)) - | (1LL << (CodeCompletionContext::CCC_Statement - 1)) - | (1LL << (CodeCompletionContext::CCC_Expression - 1)) - | (1LL << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) - | (1LL << (CodeCompletionContext::CCC_DotMemberAccess - 1)) - | (1LL << (CodeCompletionContext::CCC_ArrowMemberAccess - 1)) - | (1LL << (CodeCompletionContext::CCC_ObjCPropertyAccess - 1)) - | (1LL << (CodeCompletionContext::CCC_ObjCProtocolName - 1)) - | (1LL << (CodeCompletionContext::CCC_ParenthesizedExpression - 1)) - | (1LL << (CodeCompletionContext::CCC_Recovery - 1)); + = (1LL << CodeCompletionContext::CCC_TopLevel) + | (1LL << CodeCompletionContext::CCC_ObjCInterface) + | (1LL << CodeCompletionContext::CCC_ObjCImplementation) + | (1LL << CodeCompletionContext::CCC_ObjCIvarList) + | (1LL << CodeCompletionContext::CCC_Statement) + | (1LL << CodeCompletionContext::CCC_Expression) + | (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver) + | (1LL << CodeCompletionContext::CCC_DotMemberAccess) + | (1LL << CodeCompletionContext::CCC_ArrowMemberAccess) + | (1LL << CodeCompletionContext::CCC_ObjCPropertyAccess) + | (1LL << CodeCompletionContext::CCC_ObjCProtocolName) + | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression) + | (1LL << CodeCompletionContext::CCC_Recovery); if (AST.getASTContext().getLangOpts().CPlusPlus) - NormalContexts |= (1LL << (CodeCompletionContext::CCC_EnumTag - 1)) - | (1LL << (CodeCompletionContext::CCC_UnionTag - 1)) - | (1LL << (CodeCompletionContext::CCC_ClassOrStructTag - 1)); + NormalContexts |= (1LL << CodeCompletionContext::CCC_EnumTag) + | (1LL << CodeCompletionContext::CCC_UnionTag) + | (1LL << CodeCompletionContext::CCC_ClassOrStructTag); } virtual void ProcessCodeCompleteResults(Sema &S, @@ -2180,9 +2206,9 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, unsigned NumResults) { // Merge the results we were given with the results we cached. bool AddedResult = false; - unsigned InContexts - = (Context.getKind() == CodeCompletionContext::CCC_Recovery? NormalContexts - : (1ULL << (Context.getKind() - 1))); + uint64_t InContexts = + Context.getKind() == CodeCompletionContext::CCC_Recovery + ? NormalContexts : (1LL << Context.getKind()); // Contains the set of names that are hidden by "local" completion results. llvm::StringSet<llvm::BumpPtrAllocator> HiddenNames; typedef CodeCompletionResult Result; @@ -2273,6 +2299,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, unsigned NumRemappedFiles, bool IncludeMacros, bool IncludeCodePatterns, + bool IncludeBriefComments, CodeCompleteConsumer &Consumer, DiagnosticsEngine &Diag, LangOptions &LangOpts, SourceManager &SourceMgr, FileManager &FileMgr, @@ -2289,13 +2316,17 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, CCInvocation(new CompilerInvocation(*Invocation)); FrontendOptions &FrontendOpts = CCInvocation->getFrontendOpts(); + CodeCompleteOptions &CodeCompleteOpts = FrontendOpts.CodeCompleteOpts; PreprocessorOptions &PreprocessorOpts = CCInvocation->getPreprocessorOpts(); - FrontendOpts.ShowMacrosInCodeCompletion - = IncludeMacros && CachedCompletionResults.empty(); - FrontendOpts.ShowCodePatternsInCodeCompletion = IncludeCodePatterns; - FrontendOpts.ShowGlobalSymbolsInCodeCompletion - = CachedCompletionResults.empty(); + CodeCompleteOpts.IncludeMacros = IncludeMacros && + CachedCompletionResults.empty(); + CodeCompleteOpts.IncludeCodePatterns = IncludeCodePatterns; + CodeCompleteOpts.IncludeGlobals = CachedCompletionResults.empty(); + CodeCompleteOpts.IncludeBriefComments = IncludeBriefComments; + + assert(IncludeBriefComments == this->IncludeBriefCommentsInCodeCompletion); + FrontendOpts.CodeCompletionAt.FileName = File; FrontendOpts.CodeCompletionAt.Line = Line; FrontendOpts.CodeCompletionAt.Column = Column; @@ -2364,10 +2395,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, // Use the code completion consumer we were given, but adding any cached // code-completion results. AugmentedCodeCompleteConsumer *AugmentedConsumer - = new AugmentedCodeCompleteConsumer(*this, Consumer, - FrontendOpts.ShowMacrosInCodeCompletion, - FrontendOpts.ShowCodePatternsInCodeCompletion, - FrontendOpts.ShowGlobalSymbolsInCodeCompletion); + = new AugmentedCodeCompleteConsumer(*this, Consumer, CodeCompleteOpts); Clang->setCodeCompletionConsumer(AugmentedConsumer); Clang->getFrontendOpts().SkipFunctionBodies = true; diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 2bee240..0566d54 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -1,14 +1,3 @@ -set( LLVM_USED_LIBS - clangAST - clangBasic - clangDriver - clangEdit - clangLex - clangParse - clangSema - clangSerialization - ) - add_clang_library(clangFrontend ASTConsumers.cpp ASTMerge.cpp @@ -41,21 +30,29 @@ add_clang_library(clangFrontend Warnings.cpp ) -IF(MSVC) - get_target_property(NON_ANSI_COMPILE_FLAGS clangFrontend COMPILE_FLAGS) - string(REPLACE /Za - "" NON_ANSI_COMPILE_FLAGS - ${NON_ANSI_COMPILE_FLAGS}) - set_target_properties(clangFrontend PROPERTIES COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS}) -ENDIF(MSVC) - -add_dependencies(clangFrontend +add_dependencies(clangFrontend ClangAttrClasses ClangAttrList - ClangCC1Options - ClangDiagnosticFrontend + ClangAttrParsedAttrList + ClangCommentNodes + ClangDeclNodes + ClangDiagnosticAST + ClangDiagnosticCommon + ClangDiagnosticDriver + ClangDiagnosticFrontend ClangDiagnosticLex ClangDiagnosticSema ClangDriverOptions - ClangDeclNodes - ClangStmtNodes) + ClangStmtNodes + ) + +target_link_libraries(clangFrontend + clangAST + clangBasic + clangDriver + clangEdit + clangLex + clangParse + clangSema + clangSerialization + ) diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 803e418..6de1531 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -387,9 +387,7 @@ void CompilerInstance::createCodeCompletionConsumer() { setCodeCompletionConsumer( createCodeCompletionConsumer(getPreprocessor(), Loc.FileName, Loc.Line, Loc.Column, - getFrontendOpts().ShowMacrosInCodeCompletion, - getFrontendOpts().ShowCodePatternsInCodeCompletion, - getFrontendOpts().ShowGlobalSymbolsInCodeCompletion, + getFrontendOpts().CodeCompleteOpts, llvm::outs())); if (!CompletionConsumer) return; @@ -415,16 +413,13 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename, unsigned Line, unsigned Column, - bool ShowMacros, - bool ShowCodePatterns, - bool ShowGlobals, + const CodeCompleteOptions &Opts, raw_ostream &OS) { if (EnableCodeCompletion(PP, Filename, Line, Column)) return 0; // Set up the creation routine for code-completion. - return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, - ShowGlobals, OS); + return new PrintingCodeCompleteConsumer(Opts, OS); } void CompilerInstance::createSema(TranslationUnitKind TUKind, @@ -456,7 +451,7 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) { FileMgr->FixupRelativePath(NewOutFile); if (llvm::error_code ec = llvm::sys::fs::rename(it->TempFilename, NewOutFile.str())) { - getDiagnostics().Report(diag::err_fe_unable_to_rename_temp) + getDiagnostics().Report(diag::err_unable_to_rename_temp) << it->TempFilename << it->Filename << ec.message(); bool existed; @@ -560,7 +555,8 @@ CompilerInstance::createOutputFile(StringRef OutputPath, TempPath += "-%%%%%%%%"; int fd; if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath, - /*makeAbsolute=*/false) == llvm::errc::success) { + /*makeAbsolute=*/false, 0664) + == llvm::errc::success) { OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true)); OSFile = TempFile = TempPath.str(); } @@ -859,13 +855,6 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, } // Determine what file we're searching from. - SourceManager &SourceMgr = getSourceManager(); - SourceLocation ExpandedImportLoc = SourceMgr.getExpansionLoc(ImportLoc); - const FileEntry *CurFile - = SourceMgr.getFileEntryForID(SourceMgr.getFileID(ExpandedImportLoc)); - if (!CurFile) - CurFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()); - StringRef ModuleName = Path[0].first->getName(); SourceLocation ModuleNameLoc = Path[0].second; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 4c5b063..d39679c 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -13,7 +13,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" -#include "clang/Driver/CC1Options.h" +#include "clang/Driver/Options.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" @@ -181,8 +181,21 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, ToArgsList &Res) { } static void CodeGenOptsToArgs(const CodeGenOptions &Opts, ToArgsList &Res) { - if (Opts.DebugInfo) - Res.push_back("-g"); + switch (Opts.DebugInfo) { + case CodeGenOptions::NoDebugInfo: + break; + case CodeGenOptions::DebugLineTablesOnly: + Res.push_back("-gline-tables-only"); + break; + case CodeGenOptions::LimitedDebugInfo: + Res.push_back("-g"); + Res.push_back("-flimit-debug-info"); + break; + case CodeGenOptions::FullDebugInfo: + Res.push_back("-g"); + Res.push_back("-fno-limit-debug-info"); + break; + } if (Opts.DisableLLVMOpts) Res.push_back("-disable-llvm-optzns"); if (Opts.DisableRedZone) @@ -193,14 +206,12 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, ToArgsList &Res) { Res.push_back("-fdebug-compilation-dir", Opts.DebugCompilationDir); if (!Opts.DwarfDebugFlags.empty()) Res.push_back("-dwarf-debug-flags", Opts.DwarfDebugFlags); - if (Opts.ObjCRuntimeHasARC) - Res.push_back("-fobjc-runtime-has-arc"); - if (Opts.ObjCRuntimeHasTerminate) - Res.push_back("-fobjc-runtime-has-terminate"); if (Opts.EmitGcovArcs) Res.push_back("-femit-coverage-data"); if (Opts.EmitGcovNotes) Res.push_back("-femit-coverage-notes"); + if (Opts.EmitOpenCLArgMetadata) + Res.push_back("-cl-kernel-arg-info"); if (!Opts.MergeAllConstants) Res.push_back("-fno-merge-all-constants"); if (Opts.NoCommon) @@ -270,6 +281,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, ToArgsList &Res) { Res.push_back("-fobjc-dispatch-method=non-legacy"); break; } + if (Opts.BoundsChecking > 0) + Res.push_back("-fbounds-checking=" + llvm::utostr(Opts.BoundsChecking)); if (Opts.NumRegisterParameters) Res.push_back("-mregparm", llvm::utostr(Opts.NumRegisterParameters)); if (Opts.NoGlobalMerge) @@ -296,6 +309,20 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, ToArgsList &Res) { Res.push_back("-disable-llvm-verifier"); for (unsigned i = 0, e = Opts.BackendOptions.size(); i != e; ++i) Res.push_back("-backend-option", Opts.BackendOptions[i]); + + switch (Opts.DefaultTLSModel) { + case CodeGenOptions::GeneralDynamicTLSModel: + break; + case CodeGenOptions::LocalDynamicTLSModel: + Res.push_back("-ftls-model=local-dynamic"); + break; + case CodeGenOptions::InitialExecTLSModel: + Res.push_back("-ftls-model=initial-exec"); + break; + case CodeGenOptions::LocalExecTLSModel: + Res.push_back("-ftls-model=local-exec"); + break; + } } static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, @@ -407,6 +434,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::PluginAction: llvm_unreachable("Invalid kind!"); + case frontend::ASTDeclList: return "-ast-list"; case frontend::ASTDump: return "-ast-dump"; case frontend::ASTDumpXML: return "-ast-dump-xml"; case frontend::ASTPrint: return "-ast-print"; @@ -445,6 +473,18 @@ static void FileSystemOptsToArgs(const FileSystemOptions &Opts, ToArgsList &Res) Res.push_back("-working-directory", Opts.WorkingDir); } +static void CodeCompleteOptionsToArgs(const CodeCompleteOptions &Opts, + ToArgsList &Res) { + if (Opts.IncludeMacros) + Res.push_back("-code-completion-macros"); + if (Opts.IncludeCodePatterns) + Res.push_back("-code-completion-patterns"); + if (!Opts.IncludeGlobals) + Res.push_back("-no-code-completion-globals"); + if (Opts.IncludeBriefComments) + Res.push_back("-code-completion-brief-comments"); +} + static void FrontendOptsToArgs(const FrontendOptions &Opts, ToArgsList &Res) { if (Opts.DisableFree) Res.push_back("-disable-free"); @@ -452,12 +492,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, ToArgsList &Res) { Res.push_back("-relocatable-pch"); if (Opts.ShowHelp) Res.push_back("-help"); - if (Opts.ShowMacrosInCodeCompletion) - Res.push_back("-code-completion-macros"); - if (Opts.ShowCodePatternsInCodeCompletion) - Res.push_back("-code-completion-patterns"); - if (!Opts.ShowGlobalSymbolsInCodeCompletion) - Res.push_back("-no-code-completion-globals"); if (Opts.ShowStats) Res.push_back("-print-stats"); if (Opts.ShowTimers) @@ -485,6 +519,7 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, ToArgsList &Res) { Res.push_back("-arcmt-migrate"); break; } + CodeCompleteOptionsToArgs(Opts.CodeCompleteOpts, Res); if (!Opts.MTMigrateDir.empty()) Res.push_back("-mt-migrate-directory", Opts.MTMigrateDir); if (!Opts.ARCMTMigrateReportOut.empty()) @@ -524,6 +559,8 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, ToArgsList &Res) { for(unsigned i = 0, e = Opts.PluginArgs.size(); i != e; ++i) Res.push_back("-plugin-arg-" + Opts.ActionName, Opts.PluginArgs[i]); } + if (!Opts.ASTDumpFilter.empty()) + Res.push_back("-ast-dump-filter", Opts.ASTDumpFilter); for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) Res.push_back("-load", Opts.Plugins[i]); for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { @@ -608,6 +645,16 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, Res.push_back(E.Path); } + /// User-specified system header prefixes. + for (unsigned i = 0, e = Opts.SystemHeaderPrefixes.size(); i != e; ++i) { + if (Opts.SystemHeaderPrefixes[i].IsSystemHeader) + Res.push_back("-isystem-prefix"); + else + Res.push_back("-ino-system-prefix"); + + Res.push_back(Opts.SystemHeaderPrefixes[i].Prefix); + } + if (!Opts.ResourceDir.empty()) Res.push_back("-resource-dir", Opts.ResourceDir); if (!Opts.ModuleCachePath.empty()) @@ -653,8 +700,6 @@ static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) { Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion)); if (Opts.Borland) Res.push_back("-fborland-extensions"); - if (!Opts.ObjCNonFragileABI) - Res.push_back("-fobjc-fragile-abi"); if (Opts.ObjCDefaultSynthProperties) Res.push_back("-fobjc-default-synthesize-properties"); // NoInline is implicit. @@ -690,8 +735,6 @@ static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) { Res.push_back("-fno-rtti"); if (Opts.MSBitfields) Res.push_back("-mms-bitfields"); - if (!Opts.NeXTRuntime) - Res.push_back("-fgnu-runtime"); if (Opts.Freestanding) Res.push_back("-ffreestanding"); if (Opts.NoBuiltin) @@ -721,6 +764,11 @@ static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) { Res.push_back("-ftrapv-handler", Opts.OverflowHandler); break; } + switch (Opts.getFPContractMode()) { + case LangOptions::FPC_Off: Res.push_back("-ffp-contract=off"); break; + case LangOptions::FPC_On: Res.push_back("-ffp-contract=on"); break; + case LangOptions::FPC_Fast: Res.push_back("-ffp-contract=fast"); break; + } if (Opts.HeinousExtensions) Res.push_back("-fheinous-gnu-extensions"); // Optimize is implicit. @@ -761,6 +809,7 @@ static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) { Res.push_back("-fobjc-gc-only"); } } + Res.push_back("-fobjc-runtime=" + Opts.ObjCRuntime.getAsString()); if (Opts.ObjCAutoRefCount) Res.push_back("-fobjc-arc"); if (Opts.ObjCRuntimeHasWeak) @@ -770,7 +819,7 @@ static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) { if (Opts.AppleKext) Res.push_back("-fapple-kext"); - + if (Opts.getVisibilityMode() != DefaultVisibility) { Res.push_back("-fvisibility"); if (Opts.getVisibilityMode() == HiddenVisibility) { @@ -880,7 +929,7 @@ static void TargetOptsToArgs(const TargetOptions &Opts, Res.push_back("-target-feature", Opts.Features[i]); } -void CompilerInvocation::toArgs(std::vector<std::string> &Res) { +void CompilerInvocation::toArgs(std::vector<std::string> &Res) const { ToArgsList List(Res); AnalyzerOptsToArgs(getAnalyzerOpts(), List); CodeGenOptsToArgs(getCodeGenOpts(), List); @@ -900,7 +949,7 @@ void CompilerInvocation::toArgs(std::vector<std::string> &Res) { //===----------------------------------------------------------------------===// using namespace clang::driver; -using namespace clang::driver::cc1options; +using namespace clang::driver::options; // @@ -909,14 +958,66 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, unsigned DefaultOpt = 0; if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable)) DefaultOpt = 2; - // -Os/-Oz implies -O2 - return (Args.hasArg(OPT_Os) || Args.hasArg (OPT_Oz)) ? 2 : - Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags); + + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (A->getOption().matches(options::OPT_O0)) + return 0; + + assert (A->getOption().matches(options::OPT_O)); + + llvm::StringRef S(A->getValue(Args)); + if (S == "s" || S == "z" || S.empty()) + return 2; + + return Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags); + } + + return DefaultOpt; +} + +static unsigned getOptimizationLevelSize(ArgList &Args, InputKind IK, + DiagnosticsEngine &Diags) { + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (A->getOption().matches(options::OPT_O)) { + switch (A->getValue(Args)[0]) { + default: + return 0; + case 's': + return 1; + case 'z': + return 2; + } + } + } + return 0; +} + +static void addWarningArgs(ArgList &Args, std::vector<std::string> &Warnings) { + for (arg_iterator I = Args.filtered_begin(OPT_W_Group), + E = Args.filtered_end(); I != E; ++I) { + Arg *A = *I; + // If the argument is a pure flag, add its name (minus the "-W" at the beginning) + // to the warning list. Else, add its value (for the OPT_W case). + if (A->getOption().getKind() == Option::FlagClass) { + Warnings.push_back(A->getOption().getName().substr(2)); + } else { + for (unsigned Idx = 0, End = A->getNumValues(); + Idx < End; ++Idx) { + StringRef V = A->getValue(Args, Idx); + // "-Wl," and such are not warning options. + // FIXME: Should be handled by putting these in separate flags. + if (V.startswith("l,") || V.startswith("a,") || V.startswith("p,")) + continue; + + Warnings.push_back(V); + } + } + } } static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { - using namespace cc1options; + using namespace options; bool Success = true; if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { StringRef Name = A->getValue(Args); @@ -1026,7 +1127,6 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, 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.TrimGraph = Args.hasArg(OPT_trim_egraph); Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags); @@ -1066,7 +1166,7 @@ static bool ParseMigratorArgs(MigratorOptions &Opts, ArgList &Args) { static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { - using namespace cc1options; + using namespace options; bool Success = true; unsigned OptLevel = getOptimizationLevel(Args, IK, Diags); @@ -1083,12 +1183,18 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, : CodeGenOptions::OnlyAlwaysInlining; // -fno-inline-functions overrides OptimizationLevel > 1. Opts.NoInline = Args.hasArg(OPT_fno_inline); - Opts.Inlining = Args.hasArg(OPT_fno_inline_functions) ? + Opts.Inlining = Args.hasArg(OPT_fno_inline_functions) ? CodeGenOptions::OnlyAlwaysInlining : Opts.Inlining; - Opts.DebugInfo = Args.hasArg(OPT_g); - Opts.LimitDebugInfo = !Args.hasArg(OPT_fno_limit_debug_info) - || Args.hasArg(OPT_flimit_debug_info); + if (Args.hasArg(OPT_gline_tables_only)) { + Opts.DebugInfo = CodeGenOptions::DebugLineTablesOnly; + } else if (Args.hasArg(OPT_g_Flag)) { + if (Args.hasFlag(OPT_flimit_debug_info, OPT_fno_limit_debug_info, true)) + Opts.DebugInfo = CodeGenOptions::LimitedDebugInfo; + else + Opts.DebugInfo = CodeGenOptions::FullDebugInfo; + } + Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables); @@ -1099,8 +1205,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); - Opts.OptimizeSize = Args.hasArg(OPT_Os); - Opts.OptimizeSize = Args.hasArg(OPT_Oz) ? 2 : Opts.OptimizeSize; + Opts.OptimizeSize = getOptimizationLevelSize(Args, IK, Diags); Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) || Args.hasArg(OPT_ffreestanding)); Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) || @@ -1108,8 +1213,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); - Opts.ObjCRuntimeHasARC = Args.hasArg(OPT_fobjc_runtime_has_arc); - Opts.ObjCRuntimeHasTerminate = Args.hasArg(OPT_fobjc_runtime_has_terminate); Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); @@ -1145,6 +1248,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ); + Opts.BoundsChecking = Args.getLastArgIntValue(OPT_fbounds_checking_EQ, 0, + Diags); + Opts.UseInitArray = Args.hasArg(OPT_fuse_init_array); Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections); Opts.DataSections = Args.hasArg(OPT_fdata_sections); @@ -1156,6 +1262,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes); + Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); + Opts.EmitMicrosoftInlineAsm = Args.hasArg(OPT_fenable_experimental_ms_inline_asm); Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file); @@ -1180,12 +1288,28 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } } + if (Arg *A = Args.getLastArg(OPT_ftlsmodel_EQ)) { + StringRef Name = A->getValue(Args); + unsigned Model = llvm::StringSwitch<unsigned>(Name) + .Case("global-dynamic", CodeGenOptions::GeneralDynamicTLSModel) + .Case("local-dynamic", CodeGenOptions::LocalDynamicTLSModel) + .Case("initial-exec", CodeGenOptions::InitialExecTLSModel) + .Case("local-exec", CodeGenOptions::LocalExecTLSModel) + .Default(~0U); + if (Model == ~0U) { + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; + Success = false; + } else { + Opts.DefaultTLSModel = static_cast<CodeGenOptions::TLSModel>(Model); + } + } + return Success; } static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, ArgList &Args) { - using namespace cc1options; + using namespace options; Opts.OutputFile = Args.getLastArgValue(OPT_dependency_file); Opts.Targets = Args.getAllArgValues(OPT_MT); Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps); @@ -1198,7 +1322,7 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine *Diags) { - using namespace cc1options; + using namespace options; bool Success = true; Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file); @@ -1273,6 +1397,8 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); + Opts.ElideType = !Args.hasArg(OPT_fno_elide_type); + Opts.ShowTemplateTree = Args.hasArg(OPT_fdiagnostics_show_template_tree); Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags); Opts.MacroBacktraceLimit = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit, @@ -1295,16 +1421,7 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, } Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags); Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information); - - for (arg_iterator it = Args.filtered_begin(OPT_W), - ie = Args.filtered_end(); it != ie; ++it) { - StringRef V = (*it)->getValue(Args); - // "-Wl," and such are not warnings options. - if (V.startswith("l,") || V.startswith("a,") || V.startswith("p,")) - continue; - - Opts.Warnings.push_back(V); - } + addWarningArgs(Args, Opts.Warnings); return Success; } @@ -1315,12 +1432,14 @@ static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) { static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { - using namespace cc1options; + using namespace options; Opts.ProgramAction = frontend::ParseSyntaxOnly; if (const Arg *A = Args.getLastArg(OPT_Action_Group)) { switch (A->getOption().getID()) { default: llvm_unreachable("Invalid option in group!"); + case OPT_ast_list: + Opts.ProgramAction = frontend::ASTDeclList; break; case OPT_ast_dump: Opts.ProgramAction = frontend::ASTDump; break; case OPT_ast_dump_xml: @@ -1418,11 +1537,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.Plugins = Args.getAllArgValues(OPT_load); Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); Opts.ShowHelp = Args.hasArg(OPT_help); - Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); - Opts.ShowCodePatternsInCodeCompletion - = Args.hasArg(OPT_code_completion_patterns); - Opts.ShowGlobalSymbolsInCodeCompletion - = !Args.hasArg(OPT_no_code_completion_globals); Opts.ShowStats = Args.hasArg(OPT_print_stats); Opts.ShowTimers = Args.hasArg(OPT_ftime_report); Opts.ShowVersion = Args.hasArg(OPT_version); @@ -1432,6 +1546,17 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.FixOnlyWarnings = Args.hasArg(OPT_fix_only_warnings); Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile); Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp); + Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter); + + Opts.CodeCompleteOpts.IncludeMacros + = Args.hasArg(OPT_code_completion_macros); + Opts.CodeCompleteOpts.IncludeCodePatterns + = Args.hasArg(OPT_code_completion_patterns); + Opts.CodeCompleteOpts.IncludeGlobals + = !Args.hasArg(OPT_no_code_completion_globals); + Opts.CodeCompleteOpts.IncludeBriefComments + = Args.hasArg(OPT_code_completion_brief_comments); + Opts.OverrideRecordLayoutsFile = Args.getLastArgValue(OPT_foverride_record_layout_EQ); if (const Arg *A = Args.getLastArg(OPT_arcmt_check, @@ -1535,7 +1660,7 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0, } static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { - using namespace cc1options; + using namespace options; Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); @@ -1620,6 +1745,14 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Opts.AddPath((*I)->getValue(Args), frontend::System, false, false, /*IgnoreSysRoot=*/true, /*IsInternal=*/true, (*I)->getOption().matches(OPT_internal_externc_isystem)); + + // Add the path prefixes which are implicitly treated as being system headers. + for (arg_iterator I = Args.filtered_begin(OPT_isystem_prefix, + OPT_ino_system_prefix), + E = Args.filtered_end(); + I != E; ++I) + Opts.AddSystemHeaderPrefix((*I)->getValue(Args), + (*I)->getOption().matches(OPT_isystem_prefix)); } void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, @@ -1677,9 +1810,22 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.HexFloats = Std.hasHexFloats(); Opts.ImplicitInt = Std.hasImplicitInt(); - // OpenCL has some additional defaults. + // Set OpenCL Version. if (LangStd == LangStandard::lang_opencl) { Opts.OpenCL = 1; + Opts.OpenCLVersion = 100; + } + else if (LangStd == LangStandard::lang_opencl11) { + Opts.OpenCL = 1; + Opts.OpenCLVersion = 110; + } + else if (LangStd == LangStandard::lang_opencl12) { + Opts.OpenCL = 1; + Opts.OpenCLVersion = 120; + } + + // OpenCL has some additional defaults. + if (Opts.OpenCL) { Opts.AltiVec = 0; Opts.CXXOperatorNames = 1; Opts.LaxVectorConversions = 0; @@ -1751,13 +1897,24 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, } } + // -cl-std only applies for OpenCL language standards. + // Override the -std option in this case. if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) { - if (strcmp(A->getValue(Args), "CL1.1") != 0) { + LangStandard::Kind OpenCLLangStd + = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args)) + .Case("CL", LangStandard::lang_opencl) + .Case("CL1.1", LangStandard::lang_opencl11) + .Case("CL1.2", LangStandard::lang_opencl12) + .Default(LangStandard::lang_unspecified); + + if (OpenCLLangStd == LangStandard::lang_unspecified) { Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(Args); + << A->getAsString(Args) << A->getValue(Args); } + else + LangStd = OpenCLLangStd; } - + CompilerInvocation::setLangDefaults(Opts, IK, LangStd); // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension @@ -1772,16 +1929,23 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.CXXOperatorNames = 0; if (Opts.ObjC1) { + if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) { + StringRef value = arg->getValue(Args); + if (Opts.ObjCRuntime.tryParse(value)) + Diags.Report(diag::err_drv_unknown_objc_runtime) << value; + } + if (Args.hasArg(OPT_fobjc_gc_only)) Opts.setGC(LangOptions::GCOnly); else if (Args.hasArg(OPT_fobjc_gc)) Opts.setGC(LangOptions::HybridGC); else if (Args.hasArg(OPT_fobjc_arc)) { Opts.ObjCAutoRefCount = 1; - if (Args.hasArg(OPT_fobjc_fragile_abi)) + if (!Opts.ObjCRuntime.isNonFragile()) Diags.Report(diag::err_arc_nonfragile_abi); } + Opts.ObjCRuntimeHasWeak = Opts.ObjCRuntime.hasWeak(); if (Args.hasArg(OPT_fobjc_runtime_has_weak)) Opts.ObjCRuntimeHasWeak = 1; @@ -1825,6 +1989,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; + if (Arg *A = Args.getLastArg(OPT_ffp_contract)) { + StringRef Val = A->getValue(Args); + if (Val == "fast") + Opts.setFPContractMode(LangOptions::FPC_Fast); + else if (Val == "on") + Opts.setFPContractMode(LangOptions::FPC_On); + else if (Val == "off") + Opts.setFPContractMode(LangOptions::FPC_Off); + else + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; + } + if (Args.hasArg(OPT_fvisibility_inlines_hidden)) Opts.InlineVisibilityHidden = 1; @@ -1876,25 +2052,21 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.AccessControl = !Args.hasArg(OPT_fno_access_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); Opts.MathErrno = Args.hasArg(OPT_fmath_errno); - Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024, + Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 512, Diags); Opts.ConstexprCallDepth = Args.getLastArgIntValue(OPT_fconstexpr_depth, 512, Diags); Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing); - Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy, + Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy_EQ, 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_fragile_abi); - if (Opts.ObjCNonFragileABI) - Opts.ObjCNonFragileABI2 = true; Opts.ObjCDefaultSynthProperties = Args.hasArg(OPT_fobjc_default_synthesize_properties); Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); - Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct, 0, Diags); + Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct_EQ, 0, Diags); Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags); Opts.PIELevel = Args.getLastArgIntValue(OPT_pie_level, 0, Diags); Opts.Static = Args.hasArg(OPT_static_define); @@ -1924,9 +2096,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.Deprecated); // FIXME: Eliminate this dependency. - unsigned Opt = getOptimizationLevel(Args, IK, Diags); + unsigned Opt = getOptimizationLevel(Args, IK, Diags), + OptSize = getOptimizationLevelSize(Args, IK, Diags); Opts.Optimize = Opt != 0; - Opts.OptimizeSize = Args.hasArg(OPT_Os) || Args.hasArg(OPT_Oz); + Opts.OptimizeSize = OptSize != 0; // This is the __NO_INLINE__ define, which just depends on things like the // optimization level and -fno-inline, not actually whether the backend has @@ -1934,6 +2107,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.NoInlineDefine = !Opt || Args.hasArg(OPT_fno_inline); Opts.FastMath = Args.hasArg(OPT_ffast_math); + Opts.FiniteMathOnly = Args.hasArg(OPT_ffinite_math_only); unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags); switch (SSP) { @@ -1950,7 +2124,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, FileManager &FileMgr, DiagnosticsEngine &Diags) { - using namespace cc1options; + using namespace options; Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); if (const Arg *A = Args.getLastArg(OPT_token_cache)) @@ -2052,16 +2226,17 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, ArgList &Args) { - using namespace cc1options; + using namespace options; Opts.ShowCPP = !Args.hasArg(OPT_dM); Opts.ShowComments = Args.hasArg(OPT_C); Opts.ShowLineMarkers = !Args.hasArg(OPT_P); Opts.ShowMacroComments = Args.hasArg(OPT_CC); Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD); + Opts.RewriteIncludes = Args.hasArg(OPT_frewrite_includes); } static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { - using namespace cc1options; + using namespace options; Opts.ABI = Args.getLastArgValue(OPT_target_abi); Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi); Opts.CPU = Args.getLastArgValue(OPT_target_cpu); @@ -2083,7 +2258,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, bool Success = true; // Parse the arguments. - OwningPtr<OptTable> Opts(createCC1OptTable()); + OwningPtr<OptTable> Opts(createDriverOptTable()); unsigned MissingArgIndex, MissingArgCount; OwningPtr<InputArgList> Args( Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); @@ -2102,6 +2277,15 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Success = false; } + // Issue errors on arguments that are not valid for CC1. + for (ArgList::iterator I = Args->begin(), E = Args->end(); + I != E; ++I) { + if (!(*I)->getOption().isCC1Option()) { + Diags.Report(diag::err_drv_unknown_argument) << (*I)->getAsString(*Args); + Success = false; + } + } + Success = ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags) && Success; Success = ParseMigratorArgs(Res.getMigratorOpts(), *Args) && Success; ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp index b477ade..0aca86e 100644 --- a/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -43,13 +43,17 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList, Args.push_back("<clang>"); // FIXME: Remove dummy argument. Args.insert(Args.end(), ArgList.begin(), ArgList.end()); - // FIXME: Find a cleaner way to force the driver into restricted modes. We - // also want to force it to use clang. + // FIXME: Find a cleaner way to force the driver into restricted modes. Args.push_back("-fsyntax-only"); // FIXME: We shouldn't have to pass in the path info. driver::Driver TheDriver("clang", llvm::sys::getDefaultTargetTriple(), "a.out", false, *Diags); + // Force driver to use clang. + // FIXME: This seems like a hack. Maybe the "Clang" tool subclass should be + // available for using it to get the arguments, thus avoiding the overkill + // of using the driver. + TheDriver.setForcedClangUse(); // Don't check that inputs exist, they may have been remapped. TheDriver.setCheckInputsExist(false); diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp index 6c3bb1d..f052f90 100644 --- a/lib/Frontend/DiagnosticRenderer.cpp +++ b/lib/Frontend/DiagnosticRenderer.cpp @@ -22,56 +22,6 @@ #include <algorithm> using namespace clang; -/// Look through spelling locations for a macro argument expansion, and -/// if found skip to it so that we can trace the argument rather than the macros -/// in which that argument is used. If no macro argument expansion is found, -/// don't skip anything and return the starting location. -static SourceLocation skipToMacroArgExpansion(const SourceManager &SM, - SourceLocation StartLoc) { - for (SourceLocation L = StartLoc; L.isMacroID(); - L = SM.getImmediateSpellingLoc(L)) { - if (SM.isMacroArgExpansion(L)) - return L; - } - - // Otherwise just return initial location, there's nothing to skip. - return StartLoc; -} - -/// Gets the location of the immediate macro caller, one level up the stack -/// toward the initial macro typed into the source. -static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM, - SourceLocation Loc) { - if (!Loc.isMacroID()) return Loc; - - // When we have the location of (part of) an expanded parameter, its spelling - // location points to the argument as typed into the macro call, and - // therefore is used to locate the macro caller. - if (SM.isMacroArgExpansion(Loc)) - return SM.getImmediateSpellingLoc(Loc); - - // Otherwise, the caller of the macro is located where this macro is - // expanded (while the spelling is part of the macro definition). - return SM.getImmediateExpansionRange(Loc).first; -} - -/// Gets the location of the immediate macro callee, one level down the stack -/// toward the leaf macro. -static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM, - SourceLocation Loc) { - if (!Loc.isMacroID()) return Loc; - - // When we have the location of (part of) an expanded parameter, its - // expansion location points to the unexpanded paramater reference within - // the macro definition (or callee). - if (SM.isMacroArgExpansion(Loc)) - return SM.getImmediateExpansionRange(Loc).first; - - // Otherwise, the callee of the macro is located where this location was - // spelled inside the macro definition. - return SM.getImmediateSpellingLoc(Loc); -} - /// \brief Retrieve the name of the immediate macro expansion. /// /// This routine starts from a source location, and finds the name of the macro @@ -109,24 +59,9 @@ static StringRef getImmediateMacroName(SourceLocation Loc, return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength); } -/// Get the presumed location of a diagnostic message. This computes the -/// presumed location for the top of any macro backtrace when present. -static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM, - SourceLocation Loc) { - // This is a condensed form of the algorithm used by emitCaretDiagnostic to - // walk to the top of the macro call stack. - while (Loc.isMacroID()) { - Loc = skipToMacroArgExpansion(SM, Loc); - Loc = getImmediateMacroCallerLoc(SM, Loc); - } - - return SM.getPresumedLoc(Loc); -} - -DiagnosticRenderer::DiagnosticRenderer(const SourceManager &SM, - const LangOptions &LangOpts, +DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts, const DiagnosticOptions &DiagOpts) -: SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {} +: LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {} DiagnosticRenderer::~DiagnosticRenderer() {} @@ -184,18 +119,23 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, StringRef Message, ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> FixItHints, + const SourceManager *SM, DiagOrStoredDiag D) { + assert(SM || Loc.isInvalid()); beginDiagnostic(D, Level); - PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Loc); + PresumedLoc PLoc; + if (Loc.isValid()) { + PLoc = SM->getPresumedLocForDisplay(Loc); - // First, if this diagnostic is not in the main file, print out the - // "included from" lines. - emitIncludeStack(PLoc.getIncludeLoc(), Level); + // First, if this diagnostic is not in the main file, print out the + // "included from" lines. + emitIncludeStack(PLoc.getIncludeLoc(), Level, *SM); + } // Next, emit the actual diagnostic message. - emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D); + emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D); // Only recurse if we have a valid location. if (Loc.isValid()) { @@ -205,7 +145,7 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, llvm::SmallVector<FixItHint, 8> MergedFixits; if (!FixItHints.empty()) { - mergeFixits(FixItHints, SM, LangOpts, MergedFixits); + mergeFixits(FixItHints, *SM, LangOpts, MergedFixits); FixItHints = MergedFixits; } @@ -216,7 +156,7 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, MutableRanges.push_back(I->RemoveRange); unsigned MacroDepth = 0; - emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints, + emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints, *SM, MacroDepth); } @@ -230,6 +170,8 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(), Diag.getRanges(), Diag.getFixIts(), + Diag.getLocation().isValid() ? &Diag.getLocation().getManager() + : 0, &Diag); } @@ -245,7 +187,8 @@ void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { /// \param Loc The include location of the current file (not the diagnostic /// location). void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, - DiagnosticsEngine::Level Level) { + DiagnosticsEngine::Level Level, + const SourceManager &SM) { // Skip redundant include stacks altogether. if (LastIncludeLoc == Loc) return; @@ -254,12 +197,13 @@ void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) return; - emitIncludeStackRecursively(Loc); + emitIncludeStackRecursively(Loc, SM); } /// \brief Helper to recursivly walk up the include stack and print each layer /// on the way back down. -void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc) { +void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, + const SourceManager &SM) { if (Loc.isInvalid()) return; @@ -268,10 +212,10 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc) { return; // Emit the other include frames first. - emitIncludeStackRecursively(PLoc.getIncludeLoc()); + emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM); // Emit the inclusion text/note. - emitIncludeLocation(Loc, PLoc); + emitIncludeLocation(Loc, PLoc, SM); } /// \brief Recursively emit notes for each macro expansion and caret @@ -292,6 +236,7 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( DiagnosticsEngine::Level Level, SmallVectorImpl<CharSourceRange>& Ranges, ArrayRef<FixItHint> Hints, + const SourceManager &SM, unsigned &MacroDepth, unsigned OnMacroInst) { @@ -302,26 +247,26 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( if (Loc.isFileID()) { assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!"); MacroDepth = OnMacroInst; - emitCodeContext(Loc, Level, Ranges, Hints); + emitCodeContext(Loc, Level, Ranges, Hints, SM); return; } // Otherwise recurse through each macro expansion layer. // When processing macros, skip over the expansions leading up to // a macro argument, and trace the argument's expansion stack instead. - Loc = skipToMacroArgExpansion(SM, Loc); + Loc = SM.skipToMacroArgExpansion(Loc); - SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc); + SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc); // FIXME: Map ranges? - emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, MacroDepth, + emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, SM, MacroDepth, OnMacroInst + 1); // Save the original location so we can find the spelling of the macro call. SourceLocation MacroLoc = Loc; // Map the location. - Loc = getImmediateMacroCalleeLoc(SM, Loc); + Loc = SM.getImmediateMacroCalleeLoc(Loc); unsigned MacroSkipStart = 0, MacroSkipEnd = 0; if (MacroDepth > DiagOpts.MacroBacktraceLimit && @@ -341,9 +286,9 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( I != E; ++I) { SourceLocation Start = I->getBegin(), End = I->getEnd(); if (Start.isMacroID()) - I->setBegin(getImmediateMacroCalleeLoc(SM, Start)); + I->setBegin(SM.getImmediateMacroCalleeLoc(Start)); if (End.isMacroID()) - I->setEnd(getImmediateMacroCalleeLoc(SM, End)); + I->setEnd(SM.getImmediateMacroCalleeLoc(End)); } if (Suppressed) { @@ -365,22 +310,22 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'"; emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note, Message.str(), - Ranges, ArrayRef<FixItHint>()); + Ranges, ArrayRef<FixItHint>(), &SM); } DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc, - PresumedLoc PLoc) { + PresumedLoc PLoc, + const SourceManager &SM) { // Generate a note indicating the include location. SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); Message << "in file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; - emitNote(Loc, Message.str()); + emitNote(Loc, Message.str(), &SM); } void DiagnosticNoteRenderer::emitBasicNote(StringRef Message) { - emitNote(SourceLocation(), Message); + emitNote(SourceLocation(), Message, 0); } - diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index da4bdfa..a4321e7 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -83,31 +83,31 @@ public: } }; - /// \brief Checks deserialized declarations and emits error if a name - /// matches one given in command-line using -error-on-deserialized-decl. - class DeserializedDeclsChecker : public DelegatingDeserializationListener { - ASTContext &Ctx; - std::set<std::string> NamesToCheck; - - public: - DeserializedDeclsChecker(ASTContext &Ctx, - const std::set<std::string> &NamesToCheck, - ASTDeserializationListener *Previous) - : DelegatingDeserializationListener(Previous), - Ctx(Ctx), NamesToCheck(NamesToCheck) { } - - 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(DiagnosticsEngine::Error, - "%0 was deserialized"); - Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID) - << ND->getNameAsString(); - } - - DelegatingDeserializationListener::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 DelegatingDeserializationListener { + ASTContext &Ctx; + std::set<std::string> NamesToCheck; + +public: + DeserializedDeclsChecker(ASTContext &Ctx, + const std::set<std::string> &NamesToCheck, + ASTDeserializationListener *Previous) + : DelegatingDeserializationListener(Previous), + Ctx(Ctx), NamesToCheck(NamesToCheck) { } + + 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(DiagnosticsEngine::Error, + "%0 was deserialized"); + Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID) + << ND->getNameAsString(); + } + + DelegatingDeserializationListener::DeclRead(ID, D); + } }; } // end anonymous namespace @@ -162,6 +162,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, setCurrentInput(Input); setCompilerInstance(&CI); + bool HasBegunSourceFile = false; if (!BeginInvocation(CI)) goto failure; @@ -214,6 +215,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Inform the diagnostic client we are processing a source file. CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0); + HasBegunSourceFile = true; // Initialize the action. if (!BeginSourceFileAction(CI, Input.File)) @@ -228,6 +230,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Inform the diagnostic client we are processing a source file. CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), &CI.getPreprocessor()); + HasBegunSourceFile = true; // Initialize the action. if (!BeginSourceFileAction(CI, Input.File)) @@ -309,13 +312,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.setFileManager(0); } - CI.getDiagnosticClient().EndSourceFile(); + if (HasBegunSourceFile) + CI.getDiagnosticClient().EndSourceFile(); setCurrentInput(FrontendInputFile()); setCompilerInstance(0); return false; } -void FrontendAction::Execute() { +bool FrontendAction::Execute() { CompilerInstance &CI = getCompilerInstance(); // Initialize the main file entry. This needs to be delayed until after PCH @@ -325,7 +329,7 @@ void FrontendAction::Execute() { getCurrentInput().IsSystem ? SrcMgr::C_System : SrcMgr::C_User)) - return; + return false; } if (CI.hasFrontendTimer()) { @@ -333,6 +337,8 @@ void FrontendAction::Execute() { ExecuteAction(); } else ExecuteAction(); + + return true; } void FrontendAction::EndSourceFile() { diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 737ee4a..24960cf 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -47,13 +47,18 @@ void InitOnlyAction::ExecuteAction() { ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) - return CreateASTPrinter(OS); + return CreateASTPrinter(OS, CI.getFrontendOpts().ASTDumpFilter); return 0; } ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { - return CreateASTDumper(); + return CreateASTDumper(CI.getFrontendOpts().ASTDumpFilter); +} + +ASTConsumer *ASTDeclListAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + return CreateASTDeclNodeLister(); } ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI, @@ -131,7 +136,7 @@ ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, /// /// \param Module The module we're collecting includes from. /// -/// \param Includes Will be augmented with the set of #includes or #imports +/// \param Includes Will be augmented with the set of \#includes or \#imports /// needed to load all of the named headers. static void collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 3f7e682..8178f7a 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -40,6 +40,7 @@ class InitHeaderSearch { std::vector<std::pair<IncludeDirGroup, DirectoryLookup> > IncludePath; typedef std::vector<std::pair<IncludeDirGroup, DirectoryLookup> >::const_iterator path_iterator; + std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes; HeaderSearch &Headers; bool Verbose; std::string IncludeSysroot; @@ -57,6 +58,12 @@ public: bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot = false); + /// AddSystemHeaderPrefix - Add the specified prefix to the system header + /// prefix list. + void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) { + SystemHeaderPrefixes.push_back(std::make_pair(Prefix, IsSystemHeader)); + } + /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu /// libstdc++. void AddGnuCPlusPlusIncludePaths(StringRef Base, @@ -210,6 +217,8 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, switch (os) { case llvm::Triple::FreeBSD: case llvm::Triple::NetBSD: + case llvm::Triple::OpenBSD: + case llvm::Triple::Bitrig: break; default: // FIXME: temporary hack: hard-coded paths. @@ -623,6 +632,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { bool DontSearchCurDir = false; // TODO: set to true if -I- is set? Headers.SetSearchPaths(SearchList, NumQuoted, NumAngled, DontSearchCurDir); + Headers.SetSystemHeaderPrefixes(SystemHeaderPrefixes); + // If verbose, print the list of directories that will be searched. if (Verbose) { llvm::errs() << "#include \"...\" search starts here:\n"; @@ -660,6 +671,10 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, Init.AddDefaultIncludePaths(Lang, Triple, HSOpts); + for (unsigned i = 0, e = HSOpts.SystemHeaderPrefixes.size(); i != e; ++i) + Init.AddSystemHeaderPrefix(HSOpts.SystemHeaderPrefixes[i].Prefix, + HSOpts.SystemHeaderPrefixes[i].IsSystemHeader); + if (HSOpts.UseBuiltinIncludes) { // Set up the builtin include directory in the module map. llvm::sys::Path P(HSOpts.ResourceDir); diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 93d49b0..1440da6 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -49,7 +49,7 @@ static void DefineBuiltinMacro(MacroBuilder &Builder, StringRef Macro, } } -/// AddImplicitInclude - Add an implicit #include of the specified file to the +/// AddImplicitInclude - Add an implicit \#include of the specified file to the /// predefines buffer. static void AddImplicitInclude(MacroBuilder &Builder, StringRef File, FileManager &FileMgr) { @@ -66,8 +66,8 @@ static void AddImplicitIncludeMacros(MacroBuilder &Builder, Builder.append("##"); // ##? } -/// AddImplicitIncludePTH - Add an implicit #include using the original file -/// used to generate a PTH cache. +/// AddImplicitIncludePTH - Add an implicit \#include using the original file +/// used to generate a PTH cache. static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP, StringRef ImplicitIncludePTH) { PTHManager *P = PP.getPTHManager(); @@ -288,20 +288,16 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, else if (!LangOpts.GNUMode && LangOpts.Digraphs) Builder.defineMacro("__STDC_VERSION__", "199409L"); } else { - if (LangOpts.GNUMode) - Builder.defineMacro("__cplusplus"); - else { - // C++0x [cpp.predefined]p1: - // The name_ _cplusplus is defined to the value 201103L when compiling a - // C++ translation unit. - if (LangOpts.CPlusPlus0x) - Builder.defineMacro("__cplusplus", "201103L"); - // C++03 [cpp.predefined]p1: - // The name_ _cplusplus is defined to the value 199711L when compiling a - // C++ translation unit. - else - Builder.defineMacro("__cplusplus", "199711L"); - } + // C++11 [cpp.predefined]p1: + // The name __cplusplus is defined to the value 201103L when compiling a + // C++ translation unit. + if (LangOpts.CPlusPlus0x) + Builder.defineMacro("__cplusplus", "201103L"); + // C++03 [cpp.predefined]p1: + // The name __cplusplus is defined to the value 199711L when compiling a + // C++ translation unit. + else + Builder.defineMacro("__cplusplus", "199711L"); } if (LangOpts.ObjC1) @@ -369,7 +365,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__"); if (LangOpts.ObjC1) { - if (LangOpts.ObjCNonFragileABI) { + if (LangOpts.ObjCRuntime.isNonFragile()) { Builder.defineMacro("__OBJC2__"); if (LangOpts.ObjCExceptions) @@ -379,8 +375,13 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.getGC() != LangOptions::NonGC) Builder.defineMacro("__OBJC_GC__"); - if (LangOpts.NeXTRuntime) + if (LangOpts.ObjCRuntime.isNeXTFamily()) Builder.defineMacro("__NEXT_RUNTIME__"); + + Builder.defineMacro("IBOutlet", "__attribute__((iboutlet))"); + Builder.defineMacro("IBOutletCollection(ClassName)", + "__attribute__((iboutletcollection(ClassName)))"); + Builder.defineMacro("IBAction", "void)__attribute__((ibaction)"); } // darwin_constant_cfstrings controls this. This is also dependent @@ -444,6 +445,26 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Initialize target-specific preprocessor defines. + // __BYTE_ORDER__ was added in GCC 4.6. It's analogous + // to the macro __BYTE_ORDER (no trailing underscores) + // from glibc's <endian.h> header. + // We don't support the PDP-11 as a target, but include + // the define so it can still be compared against. + Builder.defineMacro("__ORDER_LITTLE_ENDIAN__", "1234"); + Builder.defineMacro("__ORDER_BIG_ENDIAN__", "4321"); + Builder.defineMacro("__ORDER_PDP_ENDIAN__", "3412"); + if (TI.isBigEndian()) + Builder.defineMacro("__BYTE_ORDER__", "__ORDER_BIG_ENDIAN__"); + else + Builder.defineMacro("__BYTE_ORDER__", "__ORDER_LITTLE_ENDIAN__"); + + + if (TI.getPointerWidth(0) == 64 && TI.getLongWidth() == 64 + && TI.getIntWidth() == 32) { + Builder.defineMacro("_LP64"); + Builder.defineMacro("__LP64__"); + } + // Define type sizing macros based on the target properties. assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far"); Builder.defineMacro("__CHAR_BIT__", "8"); @@ -501,6 +522,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (!LangOpts.CharIsSigned) Builder.defineMacro("__CHAR_UNSIGNED__"); + if (!TargetInfo::isTypeSigned(TI.getWCharType())) + Builder.defineMacro("__WCHAR_UNSIGNED__"); + if (!TargetInfo::isTypeSigned(TI.getWIntType())) Builder.defineMacro("__WINT_UNSIGNED__"); @@ -520,15 +544,13 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (TI.getLongLongWidth() > TI.getLongWidth()) DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Builder); - // Add __builtin_va_list typedef. - Builder.append(TI.getVAListDeclaration()); - if (const char *Prefix = TI.getUserLabelPrefix()) Builder.defineMacro("__USER_LABEL_PREFIX__", Prefix); - // Build configuration options. FIXME: these should be controlled by - // command line options or something. - Builder.defineMacro("__FINITE_MATH_ONLY__", "0"); + if (LangOpts.FastMath || LangOpts.FiniteMathOnly) + Builder.defineMacro("__FINITE_MATH_ONLY__", "1"); + else + Builder.defineMacro("__FINITE_MATH_ONLY__", "0"); if (LangOpts.GNUInline) Builder.defineMacro("__GNUC_GNU_INLINE__"); diff --git a/lib/Frontend/LayoutOverrideSource.cpp b/lib/Frontend/LayoutOverrideSource.cpp index eb7865e..e023250 100644 --- a/lib/Frontend/LayoutOverrideSource.cpp +++ b/lib/Frontend/LayoutOverrideSource.cpp @@ -9,6 +9,7 @@ #include "clang/Frontend/LayoutOverrideSource.h" #include "clang/AST/Decl.h" #include "llvm/Support/raw_ostream.h" +#include <cctype> #include <fstream> #include <string> diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 9e1587c..5311ed5 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" +#include <cctype> #include <cstdio> using namespace clang; @@ -87,7 +88,7 @@ private: unsigned CurLine; bool EmittedTokensOnThisLine; - bool EmittedMacroOnThisLine; + bool EmittedDirectiveOnThisLine; SrcMgr::CharacteristicKind FileType; SmallString<512> CurFilename; bool Initialized; @@ -103,7 +104,7 @@ public: CurLine = 0; CurFilename += "<uninit>"; EmittedTokensOnThisLine = false; - EmittedMacroOnThisLine = false; + EmittedDirectiveOnThisLine = false; FileType = SrcMgr::C_User; Initialized = false; @@ -111,10 +112,15 @@ public: UseLineDirective = PP.getLangOpts().MicrosoftExt; } - void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; } + void setEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; } bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; } - bool StartNewLineIfNeeded(); + void setEmittedDirectiveOnThisLine() { EmittedDirectiveOnThisLine = true; } + bool hasEmittedDirectiveOnThisLine() const { + return EmittedDirectiveOnThisLine; + } + + bool startNewLineIfNeeded(bool ShouldUpdateCurrentLine = true); virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, @@ -158,11 +164,7 @@ public: void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo, const char *Extra, unsigned ExtraLen) { - if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) { - OS << '\n'; - EmittedTokensOnThisLine = false; - EmittedMacroOnThisLine = false; - } + startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false); // Emit #line directives or GNU line markers depending on what mode we're in. if (UseLineDirective) { @@ -207,23 +209,21 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) { } else { // Okay, we're in -P mode, which turns off line markers. However, we still // need to emit a newline between tokens on different lines. - if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) { - OS << '\n'; - EmittedTokensOnThisLine = false; - EmittedMacroOnThisLine = false; - } + startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false); } CurLine = LineNo; return true; } -bool PrintPPOutputPPCallbacks::StartNewLineIfNeeded() { - if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) { +bool +PrintPPOutputPPCallbacks::startNewLineIfNeeded(bool ShouldUpdateCurrentLine) { + if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) { OS << '\n'; EmittedTokensOnThisLine = false; - EmittedMacroOnThisLine = false; - ++CurLine; + EmittedDirectiveOnThisLine = false; + if (ShouldUpdateCurrentLine) + ++CurLine; return true; } @@ -307,7 +307,7 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, MoveToLine(MI->getDefinitionLoc()); PrintMacroDefinition(*MacroNameTok.getIdentifierInfo(), *MI, PP, OS); - EmittedMacroOnThisLine = true; + setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok, @@ -317,12 +317,13 @@ void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok, MoveToLine(MacroNameTok.getLocation()); OS << "#undef " << MacroNameTok.getIdentifierInfo()->getName(); - EmittedMacroOnThisLine = true; + setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, const std::string &Str) { + startNewLineIfNeeded(); MoveToLine(Loc); OS << "#pragma comment(" << Kind->getName(); @@ -343,11 +344,12 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc, } OS << ')'; - EmittedTokensOnThisLine = true; + setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, StringRef Str) { + startNewLineIfNeeded(); MoveToLine(Loc); OS << "#pragma message("; @@ -366,26 +368,29 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, OS << '"'; OS << ')'; - EmittedTokensOnThisLine = true; + setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks:: PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) { + startNewLineIfNeeded(); MoveToLine(Loc); OS << "#pragma " << Namespace << " diagnostic push"; - EmittedTokensOnThisLine = true; + setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks:: PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) { + startNewLineIfNeeded(); MoveToLine(Loc); OS << "#pragma " << Namespace << " diagnostic pop"; - EmittedTokensOnThisLine = true; + setEmittedDirectiveOnThisLine(); } void PrintPPOutputPPCallbacks:: PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, diag::Mapping Map, StringRef Str) { + startNewLineIfNeeded(); MoveToLine(Loc); OS << "#pragma " << Namespace << " diagnostic "; switch (Map) { @@ -403,7 +408,7 @@ PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, break; } OS << " \"" << Str << '"'; - EmittedTokensOnThisLine = true; + setEmittedDirectiveOnThisLine(); } /// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this @@ -471,10 +476,9 @@ struct UnknownPragmaHandler : public PragmaHandler { Token &PragmaTok) { // Figure out what line we went to and insert the appropriate number of // newline characters. - Callbacks->StartNewLineIfNeeded(); + 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::eod)) { if (PragmaTok.hasLeadingSpace()) @@ -483,7 +487,7 @@ struct UnknownPragmaHandler : public PragmaHandler { Callbacks->OS.write(&TokSpell[0], TokSpell.size()); PP.LexUnexpandedToken(PragmaTok); } - Callbacks->StartNewLineIfNeeded(); + Callbacks->setEmittedDirectiveOnThisLine(); } }; } // end anonymous namespace @@ -497,6 +501,10 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, PrevPrevTok.startToken(); PrevTok.startToken(); while (1) { + if (Callbacks->hasEmittedDirectiveOnThisLine()) { + Callbacks->startNewLineIfNeeded(); + Callbacks->MoveToLine(Tok.getLocation()); + } // If this token is at the start of a line, emit newlines if needed. if (Tok.isAtStartOfLine() && Callbacks->HandleFirstTokOnLine(Tok)) { @@ -533,7 +541,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, if (Tok.getKind() == tok::comment) Callbacks->HandleNewlinesInToken(&S[0], S.size()); } - Callbacks->SetEmittedTokensOnThisLine(); + Callbacks->setEmittedTokensOnThisLine(); if (Tok.is(tok::eof)) break; diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp index 7bf8742..a20f30d 100644 --- a/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -53,10 +53,9 @@ class SDiagsRenderer : public DiagnosticNoteRenderer { RecordData &Record; public: SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record, - const SourceManager &SM, const LangOptions &LangOpts, const DiagnosticOptions &DiagOpts) - : DiagnosticNoteRenderer(SM, LangOpts, DiagOpts), + : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer), Record(Record){} virtual ~SDiagsRenderer() {} @@ -67,18 +66,21 @@ protected: DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<CharSourceRange> Ranges, + const SourceManager *SM, DiagOrStoredDiag D); virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges) {} + ArrayRef<CharSourceRange> Ranges, + const SourceManager &SM) {} - void emitNote(SourceLocation Loc, StringRef Message); + void emitNote(SourceLocation Loc, StringRef Message, const SourceManager *SM); virtual void emitCodeContext(SourceLocation Loc, DiagnosticsEngine::Level Level, SmallVectorImpl<CharSourceRange>& Ranges, - ArrayRef<FixItHint> Hints); + ArrayRef<FixItHint> Hints, + const SourceManager &SM); virtual void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level); @@ -137,15 +139,16 @@ private: unsigned getEmitFile(const char *Filename); /// \brief Add SourceLocation information the specified record. - void AddLocToRecord(SourceLocation Loc, const SourceManager &SM, + void AddLocToRecord(SourceLocation Loc, const SourceManager *SM, PresumedLoc PLoc, RecordDataImpl &Record, unsigned TokSize = 0); /// \brief Add SourceLocation information the specified record. void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record, - const SourceManager &SM, + const SourceManager *SM, unsigned TokSize = 0) { - AddLocToRecord(Loc, SM, SM.getPresumedLoc(Loc), Record, TokSize); + AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(), + Record, TokSize); } /// \brief Add CharSourceRange information the specified record. @@ -241,7 +244,7 @@ static void EmitRecordID(unsigned ID, const char *Name, } void SDiagsWriter::AddLocToRecord(SourceLocation Loc, - const SourceManager &SM, + const SourceManager *SM, PresumedLoc PLoc, RecordDataImpl &Record, unsigned TokSize) { @@ -257,19 +260,19 @@ void SDiagsWriter::AddLocToRecord(SourceLocation Loc, Record.push_back(getEmitFile(PLoc.getFilename())); Record.push_back(PLoc.getLine()); Record.push_back(PLoc.getColumn()+TokSize); - Record.push_back(SM.getFileOffset(Loc)); + Record.push_back(SM->getFileOffset(Loc)); } void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range, RecordDataImpl &Record, const SourceManager &SM) { - AddLocToRecord(Range.getBegin(), Record, SM); + AddLocToRecord(Range.getBegin(), Record, &SM); unsigned TokSize = 0; if (Range.isTokenRange()) TokSize = Lexer::MeasureTokenLength(Range.getEnd(), SM, *LangOpts); - AddLocToRecord(Range.getEnd(), Record, SM, TokSize); + AddLocToRecord(Range.getEnd(), Record, &SM, TokSize); } unsigned SDiagsWriter::getEmitFile(const char *FileName){ @@ -484,13 +487,15 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, diagBuf.clear(); Info.FormatDiagnostic(diagBuf); - SourceManager &SM = Info.getSourceManager(); - SDiagsRenderer Renderer(*this, Record, SM, *LangOpts, DiagOpts); + const SourceManager * + SM = Info.hasSourceManager() ? &Info.getSourceManager() : 0; + SDiagsRenderer Renderer(*this, Record, *LangOpts, DiagOpts); Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, diagBuf.str(), Info.getRanges(), llvm::makeArrayRef(Info.getFixItHints(), Info.getNumFixItHints()), + SM, &Info); } @@ -500,6 +505,7 @@ SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<clang::CharSourceRange> Ranges, + const SourceManager *SM, DiagOrStoredDiag D) { // Emit the RECORD_DIAG record. Writer.Record.clear(); @@ -539,7 +545,8 @@ void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D, void SDiagsRenderer::emitCodeContext(SourceLocation Loc, DiagnosticsEngine::Level Level, SmallVectorImpl<CharSourceRange> &Ranges, - ArrayRef<FixItHint> Hints) { + ArrayRef<FixItHint> Hints, + const SourceManager &SM) { // Emit Source Ranges. for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end(); it != ei; ++it) { @@ -562,7 +569,8 @@ void SDiagsRenderer::emitCodeContext(SourceLocation Loc, } } -void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message) { +void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message, + const SourceManager *SM) { Writer.Stream.EnterSubblock(BLOCK_DIAG, 4); RecordData Record; Record.push_back(RECORD_DIAG); diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index 65fb1ae..9bb3e1d 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include <algorithm> +#include <cctype> using namespace clang; @@ -31,16 +32,36 @@ static const enum raw_ostream::Colors caretColor = raw_ostream::GREEN; static const enum raw_ostream::Colors warningColor = raw_ostream::MAGENTA; +static const enum raw_ostream::Colors templateColor = + raw_ostream::CYAN; static const enum raw_ostream::Colors errorColor = raw_ostream::RED; static const enum raw_ostream::Colors fatalColor = raw_ostream::RED; // Used for changing only the bold attribute. static const enum raw_ostream::Colors savedColor = raw_ostream::SAVEDCOLOR; +/// \brief Add highlights to differences in template strings. +static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str, + bool &Normal, bool Bold) { + for (unsigned i = 0, e = Str.size(); i < e; ++i) + if (Str[i] != ToggleHighlight) { + OS << Str[i]; + } else { + if (Normal) + OS.changeColor(templateColor, true); + else { + OS.resetColor(); + if (Bold) + OS.changeColor(savedColor, true); + } + Normal = !Normal; + } +} + /// \brief Number of spaces to indent when word-wrapping. const unsigned WordWrapIndentation = 6; -int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i) { +static int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i) { int bytes = 0; while (0<i) { if (SourceLine[--i]=='\t') @@ -69,7 +90,7 @@ int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i) { /// \param TabStop used to expand tabs /// \return pair(printable text, 'true' iff original text was printable) /// -std::pair<SmallString<16>,bool> +static std::pair<SmallString<16>, bool> printableTextForNextCharacter(StringRef SourceLine, size_t *i, unsigned TabStop) { assert(i && "i must not be null"); @@ -146,7 +167,7 @@ printableTextForNextCharacter(StringRef SourceLine, size_t *i, return std::make_pair(expandedByte, false); } -void expandTabs(std::string &SourceLine, unsigned TabStop) { +static void expandTabs(std::string &SourceLine, unsigned TabStop) { size_t i = SourceLine.size(); while (i>0) { i--; @@ -164,7 +185,7 @@ void expandTabs(std::string &SourceLine, unsigned TabStop) { /// characters will appear at (numbering the first column as 0). /// /// If a byte 'i' corresponds to muliple columns (e.g. the byte contains a tab -/// character) then the the array will map that byte to the first column the +/// character) then the array will map that byte to the first column the /// tab appears at and the next value in the map will have been incremented /// more than once. /// @@ -179,9 +200,9 @@ void expandTabs(std::string &SourceLine, unsigned TabStop) { /// /// "a \t \u3042" -> {0,1,2,8,9,-1,-1,11} /// -/// (\u3042 is represented in UTF-8 by three bytes and takes two columns to +/// (\\u3042 is represented in UTF-8 by three bytes and takes two columns to /// display) -void byteToColumn(StringRef SourceLine, unsigned TabStop, +static void byteToColumn(StringRef SourceLine, unsigned TabStop, SmallVectorImpl<int> &out) { out.clear(); @@ -213,9 +234,9 @@ void byteToColumn(StringRef SourceLine, unsigned TabStop, /// /// "a \t \u3042" -> {0,1,2,-1,-1,-1,-1,-1,3,4,-1,7} /// -/// (\u3042 is represented in UTF-8 by three bytes and takes two columns to +/// (\\u3042 is represented in UTF-8 by three bytes and takes two columns to /// display) -void columnToByte(StringRef SourceLine, unsigned TabStop, +static void columnToByte(StringRef SourceLine, unsigned TabStop, SmallVectorImpl<int> &out) { out.clear(); @@ -307,11 +328,11 @@ static void selectInterestingSourceRegion(std::string &SourceLine, // correctly. unsigned CaretStart = 0, CaretEnd = CaretLine.size(); for (; CaretStart != CaretEnd; ++CaretStart) - if (!isspace(CaretLine[CaretStart])) + if (!isspace(static_cast<unsigned char>(CaretLine[CaretStart]))) break; for (; CaretEnd != CaretStart; --CaretEnd) - if (!isspace(CaretLine[CaretEnd - 1])) + if (!isspace(static_cast<unsigned char>(CaretLine[CaretEnd - 1]))) break; // caret has already been inserted into CaretLine so the above whitespace @@ -322,17 +343,33 @@ static void selectInterestingSourceRegion(std::string &SourceLine, if (!FixItInsertionLine.empty()) { unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size(); for (; FixItStart != FixItEnd; ++FixItStart) - if (!isspace(FixItInsertionLine[FixItStart])) + if (!isspace(static_cast<unsigned char>(FixItInsertionLine[FixItStart]))) break; for (; FixItEnd != FixItStart; --FixItEnd) - if (!isspace(FixItInsertionLine[FixItEnd - 1])) + if (!isspace(static_cast<unsigned char>(FixItInsertionLine[FixItEnd - 1]))) break; CaretStart = std::min(FixItStart, CaretStart); CaretEnd = std::max(FixItEnd, CaretEnd); } + // CaretEnd may have been set at the middle of a character + // If it's not at a character's first column then advance it past the current + // character. + while (static_cast<int>(CaretEnd) < map.columns() && + -1 == map.columnToByte(CaretEnd)) + ++CaretEnd; + + assert((static_cast<int>(CaretStart) > map.columns() || + -1!=map.columnToByte(CaretStart)) && + "CaretStart must not point to a column in the middle of a source" + " line character"); + assert((static_cast<int>(CaretEnd) > map.columns() || + -1!=map.columnToByte(CaretEnd)) && + "CaretEnd must not point to a column in the middle of a source line" + " character"); + // CaretLine[CaretStart, CaretEnd) contains all of the interesting // parts of the caret line. While this slice is smaller than the // number of columns we have, try to grow the slice to encompass @@ -366,12 +403,14 @@ static void selectInterestingSourceRegion(std::string &SourceLine, // Skip over any whitespace we see here; we're looking for // another bit of interesting text. while (NewStart && - (map.byteToColumn(NewStart)==-1 || isspace(SourceLine[NewStart]))) + (map.byteToColumn(NewStart)==-1 || + isspace(static_cast<unsigned char>(SourceLine[NewStart])))) --NewStart; // Skip over this bit of "interesting" text. while (NewStart && - (map.byteToColumn(NewStart)!=-1 && !isspace(SourceLine[NewStart]))) + (map.byteToColumn(NewStart)!=-1 && + !isspace(static_cast<unsigned char>(SourceLine[NewStart])))) --NewStart; // Move up to the non-whitespace character we just saw. @@ -392,12 +431,14 @@ static void selectInterestingSourceRegion(std::string &SourceLine, // Skip over any whitespace we see here; we're looking for // another bit of interesting text. while (NewEnd<SourceLine.size() && - (map.byteToColumn(NewEnd)==-1 || isspace(SourceLine[NewEnd]))) + (map.byteToColumn(NewEnd)==-1 || + isspace(static_cast<unsigned char>(SourceLine[NewEnd])))) ++NewEnd; // Skip over this bit of "interesting" text. while (NewEnd<SourceLine.size() && - (map.byteToColumn(NewEnd)!=-1 && !isspace(SourceLine[NewEnd]))) + (map.byteToColumn(NewEnd)!=-1 && + !isspace(static_cast<unsigned char>(SourceLine[NewEnd])))) ++NewEnd; unsigned NewColumns = map.byteToColumn(NewEnd) - @@ -549,6 +590,7 @@ static unsigned findEndOfWord(unsigned Start, StringRef Str, /// \param Column the column number at which the first character of \p /// Str will be printed. This will be non-zero when part of the first /// line has already been printed. +/// \param Bold if the current text should be bold /// \param Indentation the number of spaces to indent any lines beyond /// the first line. /// \returns true if word-wrapping was required, or false if the @@ -556,8 +598,10 @@ static unsigned findEndOfWord(unsigned Start, StringRef Str, static bool printWordWrapped(raw_ostream &OS, StringRef Str, unsigned Columns, unsigned Column = 0, + bool Bold = false, unsigned Indentation = WordWrapIndentation) { const unsigned Length = std::min(Str.find('\n'), Str.size()); + bool TextNormal = true; // The string used to indent each line. SmallString<16> IndentStr; @@ -581,7 +625,8 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str, OS << ' '; Column += 1; } - OS << Str.substr(WordStart, WordLength); + applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength), + TextNormal, Bold); Column += WordLength; continue; } @@ -590,22 +635,24 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str, // line. OS << '\n'; OS.write(&IndentStr[0], Indentation); - OS << Str.substr(WordStart, WordLength); + applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength), + TextNormal, Bold); Column = Indentation + WordLength; Wrapped = true; } // Append any remaning text from the message with its existing formatting. - OS << Str.substr(Length); + applyTemplateHighlighting(OS, Str.substr(Length), TextNormal, Bold); + + assert(TextNormal && "Text highlighted at end of diagnostic message."); return Wrapped; } TextDiagnostic::TextDiagnostic(raw_ostream &OS, - const SourceManager &SM, const LangOptions &LangOpts, const DiagnosticOptions &DiagOpts) - : DiagnosticRenderer(SM, LangOpts, DiagOpts), OS(OS) {} + : DiagnosticRenderer(LangOpts, DiagOpts), OS(OS) {} TextDiagnostic::~TextDiagnostic() {} @@ -615,11 +662,13 @@ TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<clang::CharSourceRange> Ranges, + const SourceManager *SM, DiagOrStoredDiag D) { uint64_t StartOfLocationInfo = OS.tell(); // Emit the location of this particular diagnostic. - emitDiagnosticLoc(Loc, PLoc, Level, Ranges); + if (Loc.isValid()) + emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM); if (DiagOpts.ShowColors) OS.resetColor(); @@ -665,20 +714,27 @@ TextDiagnostic::printDiagnosticMessage(raw_ostream &OS, StringRef Message, unsigned CurrentColumn, unsigned Columns, bool ShowColors) { + bool Bold = false; if (ShowColors) { // Print warnings, errors and fatal errors in bold, no color switch (Level) { - case DiagnosticsEngine::Warning: OS.changeColor(savedColor, true); break; - case DiagnosticsEngine::Error: OS.changeColor(savedColor, true); break; - case DiagnosticsEngine::Fatal: OS.changeColor(savedColor, true); break; + case DiagnosticsEngine::Warning: + case DiagnosticsEngine::Error: + case DiagnosticsEngine::Fatal: + OS.changeColor(savedColor, true); + Bold = true; + break; default: break; //don't bold notes } } if (Columns) - printWordWrapped(OS, Message, Columns, CurrentColumn); - else - OS << Message; + printWordWrapped(OS, Message, Columns, CurrentColumn, Bold); + else { + bool Normal = true; + applyTemplateHighlighting(OS, Message, Normal, Bold); + assert(Normal && "Formatting should have returned to normal"); + } if (ShowColors) OS.resetColor(); @@ -693,7 +749,8 @@ TextDiagnostic::printDiagnosticMessage(raw_ostream &OS, /// ranges necessary. void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, - ArrayRef<CharSourceRange> Ranges) { + ArrayRef<CharSourceRange> Ranges, + const SourceManager &SM) { if (PLoc.isInvalid()) { // At least print the file name if available: FileID FID = SM.getFileID(Loc); @@ -799,7 +856,8 @@ void TextDiagnostic::emitBasicNote(StringRef Message) { } void TextDiagnostic::emitIncludeLocation(SourceLocation Loc, - PresumedLoc PLoc) { + PresumedLoc PLoc, + const SourceManager &SM) { if (DiagOpts.ShowLocation) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; @@ -817,7 +875,8 @@ void TextDiagnostic::emitIncludeLocation(SourceLocation Loc, void TextDiagnostic::emitSnippetAndCaret( SourceLocation Loc, DiagnosticsEngine::Level Level, SmallVectorImpl<CharSourceRange>& Ranges, - ArrayRef<FixItHint> Hints) { + ArrayRef<FixItHint> Hints, + const SourceManager &SM) { assert(!Loc.isInvalid() && "must have a valid source location here"); assert(Loc.isFileID() && "must have a file location here"); @@ -840,17 +899,12 @@ void TextDiagnostic::emitSnippetAndCaret( // Get information about the buffer it points into. bool Invalid = false; - StringRef BufData = SM.getBufferData(FID, &Invalid); + const char *BufStart = SM.getBufferData(FID, &Invalid).data(); if (Invalid) return; - const char *BufStart = BufData.data(); - const char *BufEnd = BufStart + BufData.size(); - unsigned LineNo = SM.getLineNumber(FID, FileOffset); unsigned ColNo = SM.getColumnNumber(FID, FileOffset); - unsigned CaretEndColNo - = ColNo + Lexer::MeasureTokenLength(Loc, SM, LangOpts); // Rewind from the current position to the start of the line. const char *TokPtr = BufStart+FileOffset; @@ -860,14 +914,9 @@ void TextDiagnostic::emitSnippetAndCaret( // Compute the line end. Scan forward from the error position to the end of // the line. const char *LineEnd = TokPtr; - while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd!=BufEnd) + while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') ++LineEnd; - // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past - // the source line length as currently being computed. See - // test/Misc/message-length.c. - CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); - // Copy the line of code into an std::string for ease of manipulation. std::string SourceLine(LineStart, LineEnd); @@ -881,7 +930,7 @@ void TextDiagnostic::emitSnippetAndCaret( for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) - highlightRange(*I, LineNo, FID, sourceColMap, CaretLine); + highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM); // Next, insert the caret itself. ColNo = sourceColMap.byteToColumn(ColNo-1); @@ -891,7 +940,7 @@ void TextDiagnostic::emitSnippetAndCaret( std::string FixItInsertionLine = buildFixItInsertionLine(LineNo, sourceColMap, - Hints); + Hints, SM); // If the source line is too long for our terminal, select only the // "interesting" source region within that line. @@ -934,11 +983,10 @@ void TextDiagnostic::emitSnippetAndCaret( } // Print out any parseable fixit information requested by the options. - emitParseableFixits(Hints); + emitParseableFixits(Hints, SM); } -void TextDiagnostic::emitSnippet(StringRef line) -{ +void TextDiagnostic::emitSnippet(StringRef line) { if (line.empty()) return; @@ -952,8 +1000,7 @@ void TextDiagnostic::emitSnippet(StringRef line) = printableTextForNextCharacter(line, &i, DiagOpts.TabStop); bool was_printable = res.second; - if (DiagOpts.ShowColors - && was_printable==print_reversed) { + if (DiagOpts.ShowColors && was_printable == print_reversed) { if (print_reversed) OS.reverseColor(); OS << to_print; @@ -979,7 +1026,8 @@ void TextDiagnostic::emitSnippet(StringRef line) void TextDiagnostic::highlightRange(const CharSourceRange &R, unsigned LineNo, FileID FID, const SourceColumnMap &map, - std::string &CaretLine) { + std::string &CaretLine, + const SourceManager &SM) { if (!R.isValid()) return; SourceLocation Begin = SM.getExpansionLoc(R.getBegin()); @@ -1064,49 +1112,63 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, std::string TextDiagnostic::buildFixItInsertionLine( unsigned LineNo, const SourceColumnMap &map, - ArrayRef<FixItHint> Hints) { + ArrayRef<FixItHint> Hints, + const SourceManager &SM) { std::string FixItInsertionLine; if (Hints.empty() || !DiagOpts.ShowFixits) return FixItInsertionLine; + unsigned PrevHintEndCol = 0; for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); I != E; ++I) { if (!I->CodeToInsert.empty()) { // We have an insertion hint. Determine whether the inserted - // code is on the same line as the caret. + // code contains no newlines and is on the same line as the caret. std::pair<FileID, unsigned> HintLocInfo = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); - if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second)) { + if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && + StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) { // Insert the new code into the line just below the code // that the user wrote. - unsigned HintColNo + // Note: When modifying this function, be very careful about what is a + // "column" (printed width, platform-dependent) and what is a + // "byte offset" (SourceManager "column"). + unsigned HintByteOffset = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1; - // hint must start inside the source or right at the end - assert(HintColNo<static_cast<unsigned>(map.bytes())+1); - HintColNo = map.byteToColumn(HintColNo); - - // FIXME: if the fixit includes tabs or other characters that do not - // take up a single column per byte when displayed then - // I->CodeToInsert.size() is not a column number and we're mixing - // units (columns + bytes). We should get printable versions - // of each fixit before using them. - unsigned LastColumnModified - = HintColNo + I->CodeToInsert.size(); - - if (LastColumnModified > static_cast<unsigned>(map.bytes())) { - unsigned LastExistingColumn = map.byteToColumn(map.bytes()); - unsigned AddedColumns = LastColumnModified-LastExistingColumn; - LastColumnModified = LastExistingColumn + AddedColumns; - } else { - LastColumnModified = map.byteToColumn(LastColumnModified); - } + // The hint must start inside the source or right at the end + assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1); + unsigned HintCol = map.byteToColumn(HintByteOffset); + + // If we inserted a long previous hint, push this one forwards, and add + // an extra space to show that this is not part of the previous + // completion. This is sort of the best we can do when two hints appear + // to overlap. + // + // Note that if this hint is located immediately after the previous + // hint, no space will be added, since the location is more important. + if (HintCol < PrevHintEndCol) + HintCol = PrevHintEndCol + 1; + + // FIXME: This function handles multibyte characters in the source, but + // not in the fixits. This assertion is intended to catch unintended + // use of multibyte characters in fixits. If we decide to do this, we'll + // have to track separate byte widths for the source and fixit lines. + assert((size_t)llvm::sys::locale::columnWidth(I->CodeToInsert) == + I->CodeToInsert.size()); + + // This relies on one byte per column in our fixit hints. + // This should NOT use HintByteOffset, because the source might have + // Unicode characters in earlier columns. + unsigned LastColumnModified = HintCol + I->CodeToInsert.size(); if (LastColumnModified > FixItInsertionLine.size()) FixItInsertionLine.resize(LastColumnModified, ' '); - assert(HintColNo+I->CodeToInsert.size() <= FixItInsertionLine.size()); + std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(), - FixItInsertionLine.begin() + HintColNo); + FixItInsertionLine.begin() + HintCol); + + PrevHintEndCol = LastColumnModified; } else { FixItInsertionLine.clear(); break; @@ -1119,7 +1181,8 @@ std::string TextDiagnostic::buildFixItInsertionLine( return FixItInsertionLine; } -void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints) { +void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints, + const SourceManager &SM) { if (!DiagOpts.ShowParseableFixits) return; diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 6445a0c..382e156 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -27,7 +27,7 @@ using namespace clang; TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os, const DiagnosticOptions &diags, bool _OwnsOutputStream) - : OS(os), LangOpts(0), DiagOpts(&diags), SM(0), + : OS(os), DiagOpts(&diags), OwnsOutputStream(_OwnsOutputStream) { } @@ -38,11 +38,11 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() { void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) { - LangOpts = &LO; + // Build the TextDiagnostic utility. + TextDiag.reset(new TextDiagnostic(OS, LO, *DiagOpts)); } void TextDiagnosticPrinter::EndSourceFile() { - LangOpts = 0; TextDiag.reset(0); } @@ -79,16 +79,6 @@ static void printDiagnosticOptions(raw_ostream &OS, Started = true; } - // If the diagnostic is an extension diagnostic and not enabled by default - // then it must have been turned on with -pedantic. - bool EnabledByDefault; - if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(), - EnabledByDefault) && - !EnabledByDefault) { - OS << (Started ? "," : " [") << "-pedantic"; - Started = true; - } - StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID()); if (!Opt.empty()) { OS << (Started ? "," : " [") << "-W" << Opt; @@ -128,7 +118,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, llvm::raw_svector_ostream DiagMessageStream(OutStr); printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts); - // Keeps track of the the starting position of the location + // Keeps track of 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 // file+line+column number prefix is. @@ -152,22 +142,16 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, } // Assert that the rest of our infrastructure is setup properly. - assert(LangOpts && "Unexpected diagnostic outside source file processing"); assert(DiagOpts && "Unexpected diagnostic without options set"); assert(Info.hasSourceManager() && "Unexpected diagnostic with no source manager"); - - // Rebuild the TextDiagnostic utility if missing or the source manager has - // changed. - if (!TextDiag || SM != &Info.getSourceManager()) { - SM = &Info.getSourceManager(); - TextDiag.reset(new TextDiagnostic(OS, *SM, *LangOpts, *DiagOpts)); - } + assert(TextDiag && "Unexpected diagnostic outside source file processing"); TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(), Info.getRanges(), llvm::makeArrayRef(Info.getFixItHints(), - Info.getNumFixItHints())); + Info.getNumFixItHints()), + &Info.getSourceManager()); OS.flush(); } diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index 552282d..a9378a1 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -11,58 +11,108 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/FileManager.h" #include "clang/Frontend/VerifyDiagnosticConsumer.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" -#include <climits> +#include <cctype> using namespace clang; +typedef VerifyDiagnosticConsumer::Directive Directive; +typedef VerifyDiagnosticConsumer::DirectiveList DirectiveList; +typedef VerifyDiagnosticConsumer::ExpectedData ExpectedData; VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags) - : Diags(_Diags), PrimaryClient(Diags.getClient()), - OwnsPrimaryClient(Diags.ownsClient()), - Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) + : Diags(_Diags), + PrimaryClient(Diags.getClient()), OwnsPrimaryClient(Diags.ownsClient()), + Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), + ActiveSourceFiles(0) { Diags.takeClient(); } VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() { + assert(!ActiveSourceFiles && "Incomplete parsing of source files!"); + assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!"); CheckDiagnostics(); Diags.takeClient(); if (OwnsPrimaryClient) delete PrimaryClient; } +#ifndef NDEBUG +namespace { +class VerifyFileTracker : public PPCallbacks { + typedef VerifyDiagnosticConsumer::FilesParsedForDirectivesSet ListType; + ListType &FilesList; + SourceManager &SM; + +public: + VerifyFileTracker(ListType &FilesList, SourceManager &SM) + : FilesList(FilesList), SM(SM) { } + + /// \brief Hook into the preprocessor and update the list of parsed + /// files when the preprocessor indicates a new file is entered. + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) { + if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(Loc))) + FilesList.insert(E); + } +}; +} // End anonymous namespace. +#endif + // DiagnosticConsumer interface. void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP) { - // FIXME: Const hack, we screw up the preprocessor but in practice its ok - // because it doesn't get reused. It would be better if we could make a copy - // though. - CurrentPreprocessor = const_cast<Preprocessor*>(PP); + // Attach comment handler on first invocation. + if (++ActiveSourceFiles == 1) { + if (PP) { + CurrentPreprocessor = PP; + const_cast<Preprocessor*>(PP)->addCommentHandler(this); +#ifndef NDEBUG + VerifyFileTracker *V = new VerifyFileTracker(FilesParsedForDirectives, + PP->getSourceManager()); + const_cast<Preprocessor*>(PP)->addPPCallbacks(V); +#endif + } + } + assert((!PP || CurrentPreprocessor == PP) && "Preprocessor changed!"); PrimaryClient->BeginSourceFile(LangOpts, PP); } void VerifyDiagnosticConsumer::EndSourceFile() { - CheckDiagnostics(); - + assert(ActiveSourceFiles && "No active source files!"); PrimaryClient->EndSourceFile(); - CurrentPreprocessor = 0; + // Detach comment handler once last active source file completed. + if (--ActiveSourceFiles == 0) { + if (CurrentPreprocessor) + const_cast<Preprocessor*>(CurrentPreprocessor)->removeCommentHandler(this); + + // Check diagnostics once last file completed. + CheckDiagnostics(); + CurrentPreprocessor = 0; + } } void VerifyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { - if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) { - const SourceManager &SM = Info.getSourceManager(); - FirstErrorFID = SM.getFileID(Info.getLocation()); +#ifndef NDEBUG + if (Info.hasSourceManager()) { + FileID FID = Info.getSourceManager().getFileID(Info.getLocation()); + if (!FID.isInvalid()) + FilesWithDiagnostics.insert(FID); } +#endif // Send the diagnostic to the buffer, we will check it once we reach the end // of the source file (or are destructed). Buffer->HandleDiagnostic(DiagLevel, Info); @@ -77,54 +127,21 @@ typedef TextDiagnosticBuffer::const_iterator const_diag_iterator; namespace { -/// Directive - Abstract class representing a parsed verify directive. -/// -class Directive { -public: - static Directive* Create(bool RegexKind, const SourceLocation &Location, - const std::string &Text, unsigned Count); -public: - /// Constant representing one or more matches aka regex "+". - static const unsigned OneOrMoreCount = UINT_MAX; - - SourceLocation Location; - const std::string Text; - unsigned Count; - - virtual ~Directive() { } - - // Returns true if directive text is valid. - // Otherwise returns false and populates E. - virtual bool isValid(std::string &Error) = 0; - - // Returns true on match. - virtual bool Match(const std::string &S) = 0; - -protected: - Directive(const SourceLocation &Location, const std::string &Text, - unsigned Count) - : Location(Location), Text(Text), Count(Count) { } - -private: - Directive(const Directive&); // DO NOT IMPLEMENT - void operator=(const Directive&); // DO NOT IMPLEMENT -}; - /// StandardDirective - Directive with string matching. /// class StandardDirective : public Directive { public: - StandardDirective(const SourceLocation &Location, const std::string &Text, - unsigned Count) - : Directive(Location, Text, Count) { } + StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, + StringRef Text, unsigned Min, unsigned Max) + : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max) { } virtual bool isValid(std::string &Error) { // all strings are considered valid; even empty ones return true; } - virtual bool Match(const std::string &S) { - return S.find(Text) != std::string::npos; + virtual bool match(StringRef S) { + return S.find(Text) != StringRef::npos; } }; @@ -132,9 +149,9 @@ public: /// class RegexDirective : public Directive { public: - RegexDirective(const SourceLocation &Location, const std::string &Text, - unsigned Count) - : Directive(Location, Text, Count), Regex(Text) { } + RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, + StringRef Text, unsigned Min, unsigned Max) + : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), Regex(Text) { } virtual bool isValid(std::string &Error) { if (Regex.isValid(Error)) @@ -142,7 +159,7 @@ public: return false; } - virtual bool Match(const std::string &S) { + virtual bool match(StringRef S) { return Regex.match(S); } @@ -150,30 +167,11 @@ private: llvm::Regex Regex; }; -typedef std::vector<Directive*> DirectiveList; - -/// ExpectedData - owns directive objects and deletes on destructor. -/// -struct ExpectedData { - DirectiveList Errors; - DirectiveList Warnings; - DirectiveList Notes; - - ~ExpectedData() { - DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 }; - for (DirectiveList **PL = Lists; *PL; ++PL) { - DirectiveList * const L = *PL; - for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I) - delete *I; - } - } -}; - class ParseHelper { public: - ParseHelper(const char *Begin, const char *End) - : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { } + ParseHelper(StringRef S) + : Begin(S.begin()), End(S.end()), C(Begin), P(Begin), PEnd(NULL) { } // Return true if string literal is next. bool Next(StringRef S) { @@ -240,78 +238,134 @@ private: /// ParseDirective - Go through the comment and see if it indicates expected /// diagnostics. If so, then put them in the appropriate directive list. /// -static void ParseDirective(const char *CommentStart, unsigned CommentLen, - ExpectedData &ED, Preprocessor &PP, - SourceLocation Pos) { +/// Returns true if any valid directives were found. +static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, + SourceLocation Pos, DiagnosticsEngine &Diags) { // A single comment may contain multiple directives. - for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) { - // search for token: expected + bool FoundDirective = false; + for (ParseHelper PH(S); !PH.Done();) { + // Search for token: expected if (!PH.Search("expected")) break; PH.Advance(); - // next token: - + // Next token: - if (!PH.Next("-")) continue; PH.Advance(); - // next token: { error | warning | note } + // Next token: { error | warning | note } DirectiveList* DL = NULL; if (PH.Next("error")) - DL = &ED.Errors; + DL = ED ? &ED->Errors : NULL; else if (PH.Next("warning")) - DL = &ED.Warnings; + DL = ED ? &ED->Warnings : NULL; else if (PH.Next("note")) - DL = &ED.Notes; + DL = ED ? &ED->Notes : NULL; else continue; PH.Advance(); - // default directive kind + // If a directive has been found but we're not interested + // in storing the directive information, return now. + if (!DL) + return true; + + // Default directive kind. bool RegexKind = false; const char* KindStr = "string"; - // next optional token: - + // Next optional token: - if (PH.Next("-re")) { PH.Advance(); RegexKind = true; KindStr = "regex"; } - // skip optional whitespace + // Next optional token: @ + SourceLocation ExpectedLoc; + if (!PH.Next("@")) { + ExpectedLoc = Pos; + } else { + PH.Advance(); + unsigned Line = 0; + bool FoundPlus = PH.Next("+"); + if (FoundPlus || PH.Next("-")) { + // Relative to current line. + PH.Advance(); + bool Invalid = false; + unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid); + if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) { + if (FoundPlus) ExpectedLine += Line; + else ExpectedLine -= Line; + ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1); + } + } else { + // Absolute line number. + if (PH.Next(Line) && Line > 0) + ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1); + } + + if (ExpectedLoc.isInvalid()) { + Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), + diag::err_verify_missing_line) << KindStr; + continue; + } + PH.Advance(); + } + + // Skip optional whitespace. PH.SkipWhitespace(); - // next optional token: positive integer or a '+'. - unsigned Count = 1; - if (PH.Next(Count)) + // Next optional token: positive integer or a '+'. + unsigned Min = 1; + unsigned Max = 1; + if (PH.Next(Min)) { PH.Advance(); - else if (PH.Next("+")) { - Count = Directive::OneOrMoreCount; + // A positive integer can be followed by a '+' meaning min + // or more, or by a '-' meaning a range from min to max. + if (PH.Next("+")) { + Max = Directive::MaxCount; + PH.Advance(); + } else if (PH.Next("-")) { + PH.Advance(); + if (!PH.Next(Max) || Max < Min) { + Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), + diag::err_verify_invalid_range) << KindStr; + continue; + } + PH.Advance(); + } else { + Max = Min; + } + } else if (PH.Next("+")) { + // '+' on its own means "1 or more". + Max = Directive::MaxCount; PH.Advance(); } - // skip optional whitespace + // Skip optional whitespace. PH.SkipWhitespace(); - // next token: {{ + // Next token: {{ if (!PH.Next("{{")) { - PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), - diag::err_verify_missing_start) << KindStr; + Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), + diag::err_verify_missing_start) << KindStr; continue; } PH.Advance(); const char* const ContentBegin = PH.C; // mark content begin - // search for token: }} + // Search for token: }} if (!PH.Search("}}")) { - PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), - diag::err_verify_missing_end) << KindStr; + Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), + diag::err_verify_missing_end) << KindStr; continue; } const char* const ContentEnd = PH.P; // mark content end PH.Advance(); - // build directive text; convert \n to newlines + // Build directive text; convert \n to newlines. std::string Text; StringRef NewlineStr = "\\n"; StringRef Content(ContentBegin, ContentEnd-ContentBegin); @@ -325,25 +379,83 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen, if (Text.empty()) Text.assign(ContentBegin, ContentEnd); - // construct new directive - Directive *D = Directive::Create(RegexKind, Pos, Text, Count); + // Construct new directive. + Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text, + Min, Max); std::string Error; - if (D->isValid(Error)) + if (D->isValid(Error)) { DL->push_back(D); - else { - PP.Diag(Pos.getLocWithOffset(ContentBegin-PH.Begin), - diag::err_verify_invalid_content) + FoundDirective = true; + } else { + Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin), + diag::err_verify_invalid_content) << KindStr << Error; } } + + return FoundDirective; } -/// FindExpectedDiags - Lex the main source file to find all of the -// expected errors and warnings. -static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) { +/// HandleComment - Hook into the preprocessor and extract comments containing +/// expected errors and warnings. +bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, + SourceRange Comment) { + SourceManager &SM = PP.getSourceManager(); + SourceLocation CommentBegin = Comment.getBegin(); + + const char *CommentRaw = SM.getCharacterData(CommentBegin); + StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw); + + if (C.empty()) + return false; + + // Fold any "\<EOL>" sequences + size_t loc = C.find('\\'); + if (loc == StringRef::npos) { + ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics()); + return false; + } + + std::string C2; + C2.reserve(C.size()); + + for (size_t last = 0;; loc = C.find('\\', last)) { + if (loc == StringRef::npos || loc == C.size()) { + C2 += C.substr(last); + break; + } + C2 += C.substr(last, loc-last); + last = loc + 1; + + if (C[last] == '\n' || C[last] == '\r') { + ++last; + + // Escape \r\n or \n\r, but not \n\n. + if (last < C.size()) + if (C[last] == '\n' || C[last] == '\r') + if (C[last] != C[last-1]) + ++last; + } else { + // This was just a normal backslash. + C2 += '\\'; + } + } + + if (!C2.empty()) + ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics()); + return false; +} + +#ifndef NDEBUG +/// \brief Lex the specified source file to determine whether it contains +/// any expected-* directives. As a Lexer is used rather than a full-blown +/// Preprocessor, directives inside skipped #if blocks will still be found. +/// +/// \return true if any directives were found. +static bool findDirectives(const Preprocessor &PP, FileID FID) { // Create a raw lexer to pull all the comments out of FID. if (FID.isInvalid()) - return; + return false; SourceManager& SM = PP.getSourceManager(); // Create a lexer to lex all the tokens of the main file in raw mode. @@ -355,6 +467,7 @@ static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) { Token Tok; Tok.setKind(tok::comment); + bool Found = false; while (Tok.isNot(tok::eof)) { RawLex.Lex(Tok); if (!Tok.is(tok::comment)) continue; @@ -363,19 +476,19 @@ static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) { if (Comment.empty()) continue; // Find all expected errors/warnings/notes. - ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation()); - }; + Found |= ParseDirective(Comment, 0, SM, Tok.getLocation(), + PP.getDiagnostics()); + } + return Found; } - -/// PrintProblem - This takes a diagnostic map of the delta between expected and -/// seen diagnostics. If there's anything in it, then something unexpected -/// happened. Print the map out in a nice format and return "true". If the map -/// is empty and we're not going to print things, then return "false". -/// -static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, - const_diag_iterator diag_begin, - const_diag_iterator diag_end, - const char *Kind, bool Expected) { +#endif // !NDEBUG + +/// \brief Takes a list of diagnostics that have been generated but not matched +/// by an expected-* directive and produces a diagnostic to the user from this. +static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr, + const_diag_iterator diag_begin, + const_diag_iterator diag_end, + const char *Kind) { if (diag_begin == diag_end) return 0; SmallString<256> Fmt; @@ -388,30 +501,32 @@ static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, OS << ": " << I->second; } - Diags.Report(diag::err_verify_inconsistent_diags) - << Kind << !Expected << OS.str(); + Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit() + << Kind << /*Unexpected=*/true << OS.str(); return std::distance(diag_begin, diag_end); } -static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, - DirectiveList &DL, const char *Kind, - bool Expected) { +/// \brief Takes a list of diagnostics that were expected to have been generated +/// but were not and produces a diagnostic to the user from this. +static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr, + DirectiveList &DL, const char *Kind) { if (DL.empty()) return 0; SmallString<256> Fmt; llvm::raw_svector_ostream OS(Fmt); for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { - Directive& D = **I; - if (D.Location.isInvalid() || !SourceMgr) - OS << "\n (frontend)"; - else - OS << "\n Line " << SourceMgr->getPresumedLineNumber(D.Location); + Directive &D = **I; + OS << "\n Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc); + if (D.DirectiveLoc != D.DiagnosticLoc) + OS << " (directive at " + << SourceMgr.getFilename(D.DirectiveLoc) << ":" + << SourceMgr.getPresumedLineNumber(D.DirectiveLoc) << ")"; OS << ": " << D.Text; } - Diags.Report(diag::err_verify_inconsistent_diags) - << Kind << !Expected << OS.str(); + Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit() + << Kind << /*Unexpected=*/false << OS.str(); return DL.size(); } @@ -428,10 +543,9 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) { Directive& D = **I; - unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.Location); - bool FoundOnce = false; + unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc); - for (unsigned i = 0; i < D.Count; ++i) { + for (unsigned i = 0; i < D.Max; ++i) { DiagList::iterator II, IE; for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first); @@ -439,29 +553,22 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, continue; const std::string &RightText = II->second; - if (D.Match(RightText)) + if (D.match(RightText)) break; } if (II == IE) { - if (D.Count == D.OneOrMoreCount) { - if (!FoundOnce) - LeftOnly.push_back(*I); - // We are only interested in at least one match, so exit the loop. - break; - } // Not found. + if (i >= D.Min) break; LeftOnly.push_back(*I); } else { // Found. The same cannot be found twice. Right.erase(II); - FoundOnce = true; } } } // Now all that's left in Right are those that were not matched. - unsigned num = PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true); - num += PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(), - Label, false); + unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label); + num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label); return num; } @@ -495,8 +602,6 @@ static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, } void VerifyDiagnosticConsumer::CheckDiagnostics() { - ExpectedData ED; - // Ensure any diagnostics go to the primary client. bool OwnsCurClient = Diags.ownsClient(); DiagnosticConsumer *CurClient = Diags.takeClient(); @@ -506,32 +611,38 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() { // markers. If not then any diagnostics are unexpected. if (CurrentPreprocessor) { SourceManager &SM = CurrentPreprocessor->getSourceManager(); - // Extract expected-error strings from main file. - FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID()); - // Only check for expectations in other diagnostic locations - // if they are not the main file (via ID or FileEntry) - the main - // file has already been looked at, and its expectations must not - // be added twice. - if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID() - && (!SM.getFileEntryForID(FirstErrorFID) - || (SM.getFileEntryForID(FirstErrorFID) != - SM.getFileEntryForID(SM.getMainFileID())))) { - FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID); - FirstErrorFID = FileID(); + +#ifndef NDEBUG + // In a debug build, scan through any files that may have been missed + // during parsing and issue a fatal error if directives are contained + // within these files. If a fatal error occurs, this suggests that + // this file is being parsed separately from the main file. + HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo(); + for (FilesWithDiagnosticsSet::iterator I = FilesWithDiagnostics.begin(), + End = FilesWithDiagnostics.end(); + I != End; ++I) { + const FileEntry *E = SM.getFileEntryForID(*I); + // Don't check files already parsed or those handled as modules. + if (E && (FilesParsedForDirectives.count(E) + || HS.findModuleForHeader(E))) + continue; + + if (findDirectives(*CurrentPreprocessor, *I)) + llvm::report_fatal_error(Twine("-verify directives found after rather" + " than during normal parsing of ", + StringRef(E ? E->getName() : "(unknown)"))); } +#endif // Check that the expected diagnostics occurred. NumErrors += CheckResults(Diags, SM, *Buffer, ED); } else { - NumErrors += (PrintProblem(Diags, 0, - Buffer->err_begin(), Buffer->err_end(), - "error", false) + - PrintProblem(Diags, 0, - Buffer->warn_begin(), Buffer->warn_end(), - "warn", false) + - PrintProblem(Diags, 0, - Buffer->note_begin(), Buffer->note_end(), - "note", false)); + NumErrors += (PrintUnexpected(Diags, 0, Buffer->err_begin(), + Buffer->err_end(), "error") + + PrintUnexpected(Diags, 0, Buffer->warn_begin(), + Buffer->warn_end(), "warn") + + PrintUnexpected(Diags, 0, Buffer->note_begin(), + Buffer->note_end(), "note")); } Diags.takeClient(); @@ -539,6 +650,9 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() { // Reset the buffer, we have processed all the diagnostics in it. Buffer.reset(new TextDiagnosticBuffer()); + ED.Errors.clear(); + ED.Warnings.clear(); + ED.Notes.clear(); } DiagnosticConsumer * @@ -549,9 +663,10 @@ VerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const { return new VerifyDiagnosticConsumer(Diags); } -Directive* Directive::Create(bool RegexKind, const SourceLocation &Location, - const std::string &Text, unsigned Count) { +Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc, + SourceLocation DiagnosticLoc, StringRef Text, + unsigned Min, unsigned Max) { if (RegexKind) - return new RegexDirective(Location, Text, Count); - return new StandardDirective(Location, Text, Count); + return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max); + return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max); } diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index ec5fde0..b7d4a3b 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -53,7 +53,11 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); Diags.setShowOverloads( static_cast<DiagnosticsEngine::OverloadsShown>(Opts.ShowOverloads)); - + + Diags.setElideType(Opts.ElideType); + Diags.setPrintTemplateTree(Opts.ShowTemplateTree); + Diags.setShowColors(Opts.ShowColors); + // Handle -ferror-limit if (Opts.ErrorLimit) Diags.setErrorLimit(Opts.ErrorLimit); @@ -83,6 +87,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, bool SetDiagnostic = (Report == 0); for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { StringRef Opt = Opts.Warnings[i]; + StringRef OrigOpt = Opts.Warnings[i]; // Treat -Wformat=0 as an alias for -Wno-format. if (Opt == "format=0") @@ -130,7 +135,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) { if (Report) Diags.Report(diag::warn_unknown_warning_specifier) - << "-Werror" << ("-W" + Opt.str()); + << "-Werror" << ("-W" + OrigOpt.str()); continue; } Specifier = Opt.substr(6); @@ -158,7 +163,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) { if (Report) Diags.Report(diag::warn_unknown_warning_specifier) - << "-Wfatal-errors" << ("-W" + Opt.str()); + << "-Wfatal-errors" << ("-W" + OrigOpt.str()); continue; } Specifier = Opt.substr(13); @@ -182,7 +187,8 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, if (Report) { if (DiagIDs->getDiagnosticsInGroup(Opt, _Diags)) - EmitUnknownDiagWarning(Diags, "-W", Opt, isPositive); + EmitUnknownDiagWarning(Diags, isPositive ? "-W" : "-Wno-", Opt, + isPositive); } else { Diags.setDiagnosticGroupMapping(Opt, Mapping); } |