diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-11-18 14:59:57 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-11-18 14:59:57 +0000 |
commit | b3d5a323a5ca92ea73443499cee2f15db1ff0fb3 (patch) | |
tree | 60a1694bec5a44d15456acc880cb2f91619f66aa /lib/Frontend | |
parent | 8f57cb0305232cb53fff00ef151ca716766f3437 (diff) | |
download | src-b3d5a323a5ca92ea73443499cee2f15db1ff0fb3.tar.gz src-b3d5a323a5ca92ea73443499cee2f15db1ff0fb3.zip |
Update clang to r89205.
Notes
Notes:
svn path=/vendor/clang/dist/; revision=199482
Diffstat (limited to 'lib/Frontend')
26 files changed, 2498 insertions, 498 deletions
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index c0415bf550f8..e3cd6ddd08d6 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -18,6 +18,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" #include "llvm/Support/Compiler.h" @@ -61,14 +62,14 @@ public: return false; } - virtual bool ReadTargetTriple(const std::string &Triple) { + virtual bool ReadTargetTriple(llvm::StringRef Triple) { TargetTriple = Triple; return false; } - virtual bool ReadPredefinesBuffer(const char *PCHPredef, - unsigned PCHPredefLen, + virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef, FileID PCHBufferID, + llvm::StringRef OriginalFileName, std::string &SuggestedPredefines) { Predefines = PCHPredef; return false; @@ -132,7 +133,14 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, // PCH loaded successfully. Now create the preprocessor. // Get information about the target being compiled for. - AST->Target.reset(TargetInfo::CreateTargetInfo(TargetTriple)); + // + // FIXME: This is broken, we should store the TargetOptions in the PCH. + TargetOptions TargetOpts; + TargetOpts.ABI = ""; + TargetOpts.CPU = ""; + TargetOpts.Features.clear(); + TargetOpts.Triple = TargetTriple; + AST->Target.reset(TargetInfo::CreateTargetInfo(AST->Diags, TargetOpts)); AST->PP.reset(new Preprocessor(AST->Diags, LangInfo, *AST->Target.get(), AST->getSourceManager(), HeaderInfo)); Preprocessor &PP = *AST->PP.get(); diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index d2831fae566a..ede3d474c848 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -20,6 +20,7 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/LocalCheckers.h" +#include "clang/Analysis/ManagerRegistry.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Analysis/PathSensitive/AnalysisManager.h" #include "clang/Analysis/PathSensitive/BugReporter.h" @@ -27,7 +28,6 @@ #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Frontend/ManagerRegistry.h" #include "clang/Frontend/PathDiagnosticClients.h" #include "clang/Lex/Preprocessor.h" #include "llvm/Support/Compiler.h" @@ -44,10 +44,6 @@ static ExplodedNode::Auditor* CreateUbiViz(); // Basic type definitions. //===----------------------------------------------------------------------===// -namespace { - typedef void (*CodeAction)(AnalysisManager& Mgr, Decl *D); -} // end anonymous namespace - //===----------------------------------------------------------------------===// // Special PathDiagnosticClients. //===----------------------------------------------------------------------===// @@ -66,116 +62,135 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix, namespace { - class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer { - typedef std::vector<CodeAction> Actions; - Actions FunctionActions; - Actions ObjCMethodActions; - Actions ObjCImplementationActions; - Actions TranslationUnitActions; + class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer { + public: + typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); + + private: + typedef std::vector<CodeAction> Actions; + Actions FunctionActions; + Actions ObjCMethodActions; + Actions ObjCImplementationActions; + Actions TranslationUnitActions; - public: - ASTContext* Ctx; - const Preprocessor &PP; - const std::string OutDir; - AnalyzerOptions Opts; +public: + ASTContext* Ctx; + const Preprocessor &PP; + const std::string OutDir; + AnalyzerOptions Opts; + bool declDisplayed; - // PD is owned by AnalysisManager. - PathDiagnosticClient *PD; + // PD is owned by AnalysisManager. + PathDiagnosticClient *PD; - StoreManagerCreator CreateStoreMgr; - ConstraintManagerCreator CreateConstraintMgr; + StoreManagerCreator CreateStoreMgr; + ConstraintManagerCreator CreateConstraintMgr; - llvm::OwningPtr<AnalysisManager> Mgr; + llvm::OwningPtr<AnalysisManager> Mgr; - AnalysisConsumer(const Preprocessor& pp, - const std::string& outdir, - const AnalyzerOptions& opts) - : Ctx(0), PP(pp), OutDir(outdir), - Opts(opts), PD(0) { - DigestAnalyzerOptions(); - } + AnalysisConsumer(const Preprocessor& pp, + const std::string& outdir, + const AnalyzerOptions& opts) + : Ctx(0), PP(pp), OutDir(outdir), + Opts(opts), declDisplayed(false), PD(0) { + DigestAnalyzerOptions(); + } - void DigestAnalyzerOptions() { - // Create the PathDiagnosticClient. - if (!OutDir.empty()) { - switch (Opts.AnalysisDiagOpt) { - default: + void DigestAnalyzerOptions() { + // Create the PathDiagnosticClient. + if (!OutDir.empty()) { + switch (Opts.AnalysisDiagOpt) { + default: #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ - case PD_##NAME: PD = CREATEFN(OutDir, PP); break; + case PD_##NAME: PD = CREATEFN(OutDir, PP); break; #include "clang/Frontend/Analyses.def" - } } + } - // Create the analyzer component creators. - if (ManagerRegistry::StoreMgrCreator != 0) { - CreateStoreMgr = ManagerRegistry::StoreMgrCreator; - } - else { - switch (Opts.AnalysisStoreOpt) { - default: - assert(0 && "Unknown store manager."); + // Create the analyzer component creators. + if (ManagerRegistry::StoreMgrCreator != 0) { + CreateStoreMgr = ManagerRegistry::StoreMgrCreator; + } + else { + switch (Opts.AnalysisStoreOpt) { + default: + assert(0 && "Unknown store manager."); #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ - case NAME##Model: CreateStoreMgr = CREATEFN; break; + case NAME##Model: CreateStoreMgr = CREATEFN; break; #include "clang/Frontend/Analyses.def" - } } + } - if (ManagerRegistry::ConstraintMgrCreator != 0) - CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator; - else { - switch (Opts.AnalysisConstraintsOpt) { - default: - assert(0 && "Unknown store manager."); + if (ManagerRegistry::ConstraintMgrCreator != 0) + CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator; + else { + switch (Opts.AnalysisConstraintsOpt) { + default: + assert(0 && "Unknown store manager."); #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ - case NAME##Model: CreateConstraintMgr = CREATEFN; break; + case NAME##Model: CreateConstraintMgr = CREATEFN; break; #include "clang/Frontend/Analyses.def" - } } } - - void addCodeAction(CodeAction action) { - FunctionActions.push_back(action); - ObjCMethodActions.push_back(action); - } - - void addObjCImplementationAction(CodeAction action) { - ObjCImplementationActions.push_back(action); - } - - void addTranslationUnitAction(CodeAction action) { - TranslationUnitActions.push_back(action); + } + + void DisplayFunction(const Decl *D) { + if (!Opts.AnalyzerDisplayProgress || declDisplayed) + return; + + declDisplayed = true; + // FIXME: Is getCodeDecl() always a named decl? + if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { + const NamedDecl *ND = cast<NamedDecl>(D); + SourceManager &SM = Mgr->getASTContext().getSourceManager(); + llvm::errs() << "ANALYZE: " + << SM.getPresumedLoc(ND->getLocation()).getFilename() + << ' ' << ND->getNameAsString() << '\n'; } + } - virtual void Initialize(ASTContext &Context) { - Ctx = &Context; - Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), - PP.getLangOptions(), PD, - CreateStoreMgr, CreateConstraintMgr, - Opts.AnalyzerDisplayProgress, - Opts.VisualizeEGDot, Opts.VisualizeEGUbi, - Opts.PurgeDead, Opts.EagerlyAssume, - Opts.TrimGraph)); - } + void addCodeAction(CodeAction action) { + FunctionActions.push_back(action); + ObjCMethodActions.push_back(action); + } - virtual void HandleTopLevelDecl(DeclGroupRef D) { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) - HandleTopLevelSingleDecl(*I); - } + void addObjCImplementationAction(CodeAction action) { + ObjCImplementationActions.push_back(action); + } - void HandleTopLevelSingleDecl(Decl *D); - virtual void HandleTranslationUnit(ASTContext &C); + void addTranslationUnitAction(CodeAction action) { + TranslationUnitActions.push_back(action); + } - void HandleCode(Decl* D, Stmt* Body, Actions& actions); - }; + virtual void Initialize(ASTContext &Context) { + Ctx = &Context; + Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), + PP.getLangOptions(), PD, + CreateStoreMgr, CreateConstraintMgr, + Opts.AnalyzerDisplayProgress, + Opts.VisualizeEGDot, Opts.VisualizeEGUbi, + Opts.PurgeDead, Opts.EagerlyAssume, + Opts.TrimGraph)); + } + virtual void HandleTopLevelDecl(DeclGroupRef D) { + declDisplayed = false; + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) + HandleTopLevelSingleDecl(*I); + } + void HandleTopLevelSingleDecl(Decl *D); + virtual void HandleTranslationUnit(ASTContext &C); + void HandleCode(Decl* D, Stmt* Body, Actions& actions); +}; } // end anonymous namespace namespace llvm { - template <> struct FoldingSetTrait<CodeAction> { - static inline void Profile(CodeAction X, FoldingSetNodeID& ID) { + template <> struct FoldingSetTrait<AnalysisConsumer::CodeAction> { + static inline void Profile(AnalysisConsumer::CodeAction X, + FoldingSetNodeID& ID) { ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X))); } }; @@ -238,7 +253,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { for (Actions::iterator I = TranslationUnitActions.begin(), E = TranslationUnitActions.end(); I != E; ++I) - (*I)(*Mgr, FD); + (*I)(*this, *Mgr, FD); } if (!ObjCImplementationActions.empty()) { @@ -272,34 +287,38 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { // Dispatch on the actions. for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) - (*I)(*Mgr, D); + (*I)(*this, *Mgr, D); } //===----------------------------------------------------------------------===// // Analyses //===----------------------------------------------------------------------===// -static void ActionWarnDeadStores(AnalysisManager& mgr, Decl *D) { +static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { if (LiveVariables *L = mgr.getLiveVariables(D)) { + C.DisplayFunction(D); BugReporter BR(mgr); CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR); } } -static void ActionWarnUninitVals(AnalysisManager& mgr, Decl *D) { - if (CFG* c = mgr.getCFG(D)) +static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + if (CFG* c = mgr.getCFG(D)) { + C.DisplayFunction(D); CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic()); + } } -static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D, +static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D, GRTransferFuncs* tf) { - llvm::OwningPtr<GRTransferFuncs> TF(tf); // Display progress. - mgr.DisplayFunction(D); + C.DisplayFunction(D); // Construct the analysis engine. We first query for the LiveVariables // information to see if the CFG is valid. @@ -312,8 +331,14 @@ static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D, Eng.setTransferFunctions(tf); Eng.RegisterInternalChecks(); // FIXME: Internal checks should just // automatically register. + + if (C.Opts.EnableExperimentalInternalChecks) + RegisterExperimentalInternalChecks(Eng); + RegisterAppleChecks(Eng, *D); - + + if (C.Opts.EnableExperimentalChecks) + RegisterExperimentalChecks(Eng); // Set the graph auditor. llvm::OwningPtr<ExplodedNode::Auditor> Auditor; @@ -337,85 +362,103 @@ static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D, Eng.getBugReporter().FlushReports(); } -static void ActionCheckerCFRefAux(AnalysisManager& mgr, Decl *D, - bool GCEnabled) { +static void ActionCheckerCFRefAux(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D, bool GCEnabled) { GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(), GCEnabled, mgr.getLangOptions()); - ActionGRExprEngine(mgr, D, TF); + ActionGRExprEngine(C, mgr, D, TF); } -static void ActionCheckerCFRef(AnalysisManager& mgr, Decl *D) { +static void ActionCheckerCFRef(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { switch (mgr.getLangOptions().getGCMode()) { default: assert (false && "Invalid GC mode."); case LangOptions::NonGC: - ActionCheckerCFRefAux(mgr, D, false); + ActionCheckerCFRefAux(C, mgr, D, false); break; case LangOptions::GCOnly: - ActionCheckerCFRefAux(mgr, D, true); + ActionCheckerCFRefAux(C, mgr, D, true); break; case LangOptions::HybridGC: - ActionCheckerCFRefAux(mgr, D, false); - ActionCheckerCFRefAux(mgr, D, true); + ActionCheckerCFRefAux(C, mgr, D, false); + ActionCheckerCFRefAux(C, mgr, D, true); break; } } -static void ActionDisplayLiveVariables(AnalysisManager& mgr, Decl *D) { +static void ActionDisplayLiveVariables(AnalysisConsumer &C, + AnalysisManager& mgr, Decl *D) { if (LiveVariables* L = mgr.getLiveVariables(D)) { - mgr.DisplayFunction(D); + C.DisplayFunction(D); L->dumpBlockLiveness(mgr.getSourceManager()); } } -static void ActionCFGDump(AnalysisManager& mgr, Decl *D) { - if (CFG* c = mgr.getCFG(D)) { - mgr.DisplayFunction(D); - c->dump(mgr.getLangOptions()); +static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { + if (CFG *cfg = mgr.getCFG(D)) { + C.DisplayFunction(D); + cfg->dump(mgr.getLangOptions()); } } -static void ActionCFGView(AnalysisManager& mgr, Decl *D) { - if (CFG* c = mgr.getCFG(D)) { - mgr.DisplayFunction(D); - c->viewCFG(mgr.getLangOptions()); +static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { + if (CFG *cfg = mgr.getCFG(D)) { + C.DisplayFunction(D); + cfg->viewCFG(mgr.getLangOptions()); } } -static void ActionSecuritySyntacticChecks(AnalysisManager &mgr, Decl *D) { +static void ActionSecuritySyntacticChecks(AnalysisConsumer &C, + AnalysisManager &mgr, Decl *D) { + C.DisplayFunction(D); BugReporter BR(mgr); CheckSecuritySyntaxOnly(D, BR); } -static void ActionWarnObjCDealloc(AnalysisManager& mgr, Decl *D) { +static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly) return; + C.DisplayFunction(D); BugReporter BR(mgr); - CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR); + CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR); } -static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr, Decl *D) { +static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + C.DisplayFunction(D); BugReporter BR(mgr); - CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR); + CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR); } -static void ActionWarnObjCMethSigs(AnalysisManager& mgr, Decl *D) { +static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + C.DisplayFunction(D); BugReporter BR(mgr); - CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR); } -static void ActionInlineCall(AnalysisManager &mgr, Decl *D) { +static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, + Decl *D) { + C.DisplayFunction(D); + BugReporter BR(mgr); + CheckSizeofPointer(D, BR); +} + +static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr, + Decl *D) { if (!D) return; + C.DisplayFunction(D); llvm::OwningPtr<GRTransferFuncs> TF(CreateCallInliner(mgr.getASTContext())); // Construct the analysis engine. diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp index 13aecf171718..bc56029e73d2 100644 --- a/lib/Frontend/Backend.cpp +++ b/lib/Frontend/Backend.cpp @@ -8,12 +8,13 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTConsumers.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/Frontend/CompileOptions.h" -#include "clang/AST/ASTContext.h" #include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclGroup.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/CodeGen/CodeGenOptions.h" +#include "clang/CodeGen/ModuleBuilder.h" #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/PassManager.h" @@ -40,7 +41,8 @@ using namespace llvm; namespace { class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer { BackendAction Action; - CompileOptions CompileOpts; + CodeGenOptions CodeGenOpts; + TargetOptions TargetOpts; llvm::raw_ostream *AsmOutStream; llvm::formatted_raw_ostream FormattedOutStream; ASTContext *Context; @@ -75,11 +77,12 @@ namespace { public: BackendConsumer(BackendAction action, Diagnostic &Diags, - const LangOptions &langopts, const CompileOptions &compopts, - const std::string &infile, llvm::raw_ostream* OS, - LLVMContext& C) : + const LangOptions &langopts, const CodeGenOptions &compopts, + const TargetOptions &targetopts, const std::string &infile, + llvm::raw_ostream* OS, LLVMContext& C) : Action(action), - CompileOpts(compopts), + CodeGenOpts(compopts), + TargetOpts(targetopts), AsmOutStream(OS), LLVMIRGeneration("LLVM IR Generation Time"), CodeGenerationTime("Code Generation Time"), @@ -92,7 +95,7 @@ namespace { formatted_raw_ostream::PRESERVE_STREAM); // Enable -time-passes if -ftime-report is enabled. - llvm::TimePassesIsEnabled = CompileOpts.TimePasses; + llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; } ~BackendConsumer() { @@ -106,7 +109,7 @@ namespace { virtual void Initialize(ASTContext &Ctx) { Context = &Ctx; - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.startTimer(); Gen->Initialize(Ctx); @@ -115,7 +118,7 @@ namespace { ModuleProvider = new ExistingModuleProvider(TheModule); TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription()); - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.stopTimer(); } @@ -124,24 +127,24 @@ namespace { Context->getSourceManager(), "LLVM IR generation of declaration"); - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.startTimer(); Gen->HandleTopLevelDecl(D); - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.stopTimer(); } virtual void HandleTranslationUnit(ASTContext &C) { { PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.startTimer(); Gen->HandleTranslationUnit(C); - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.stopTimer(); } @@ -202,7 +205,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { } else if (Action == Backend_EmitLL) { getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream)); } else { - bool Fast = CompileOpts.OptimizationLevel == 0; + bool Fast = CodeGenOpts.OptimizationLevel == 0; // Create the TargetMachine for generating code. std::string Triple = TheModule->getTargetTriple(); @@ -213,12 +216,12 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { } std::string FeaturesStr; - if (CompileOpts.CPU.size() || CompileOpts.Features.size()) { + if (TargetOpts.CPU.size() || TargetOpts.Features.size()) { SubtargetFeatures Features; - Features.setCPU(CompileOpts.CPU); + Features.setCPU(TargetOpts.CPU); for (std::vector<std::string>::iterator - it = CompileOpts.Features.begin(), - ie = CompileOpts.Features.end(); it != ie; ++it) + it = TargetOpts.Features.begin(), + ie = TargetOpts.Features.end(); it != ie; ++it) Features.AddFeature(*it); FeaturesStr = Features.getString(); } @@ -237,7 +240,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { FunctionPassManager *PM = getCodeGenPasses(); CodeGenOpt::Level OptLevel = CodeGenOpt::Default; - switch (CompileOpts.OptimizationLevel) { + switch (CodeGenOpts.OptimizationLevel) { default: break; case 0: OptLevel = CodeGenOpt::None; break; case 3: OptLevel = CodeGenOpt::Aggressive; break; @@ -266,37 +269,44 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { } void BackendConsumer::CreatePasses() { + unsigned OptLevel = CodeGenOpts.OptimizationLevel; + CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining; + + // Handle disabling of LLVM optimization, where we want to preserve the + // internal module before any optimization. + if (CodeGenOpts.DisableLLVMOpts) { + OptLevel = 0; + Inlining = CodeGenOpts.NoInlining; + } + // In -O0 if checking is disabled, we don't even have per-function passes. - if (CompileOpts.VerifyModule) + if (CodeGenOpts.VerifyModule) getPerFunctionPasses()->add(createVerifierPass()); // Assume that standard function passes aren't run for -O0. - if (CompileOpts.OptimizationLevel > 0) - llvm::createStandardFunctionPasses(getPerFunctionPasses(), - CompileOpts.OptimizationLevel); + if (OptLevel > 0) + llvm::createStandardFunctionPasses(getPerFunctionPasses(), OptLevel); llvm::Pass *InliningPass = 0; - switch (CompileOpts.Inlining) { - case CompileOptions::NoInlining: break; - case CompileOptions::NormalInlining: { + switch (Inlining) { + case CodeGenOptions::NoInlining: break; + case CodeGenOptions::NormalInlining: { // Inline small functions - unsigned Threshold = (CompileOpts.OptimizeSize || - CompileOpts.OptimizationLevel < 3) ? 50 : 200; + unsigned Threshold = (CodeGenOpts.OptimizeSize || OptLevel < 3) ? 50 : 200; InliningPass = createFunctionInliningPass(Threshold); break; } - case CompileOptions::OnlyAlwaysInlining: + case CodeGenOptions::OnlyAlwaysInlining: InliningPass = createAlwaysInlinerPass(); // Respect always_inline break; } // For now we always create per module passes. PassManager *PM = getPerModulePasses(); - llvm::createStandardModulePasses(PM, CompileOpts.OptimizationLevel, - CompileOpts.OptimizeSize, - CompileOpts.UnitAtATime, - CompileOpts.UnrollLoops, - CompileOpts.SimplifyLibCalls, + llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize, + CodeGenOpts.UnitAtATime, + CodeGenOpts.UnrollLoops, + CodeGenOpts.SimplifyLibCalls, /*HaveExceptions=*/true, InliningPass); } @@ -308,7 +318,7 @@ void BackendConsumer::EmitAssembly() { if (!TheModule || !TheTargetData) return; - TimeRegion Region(CompileOpts.TimePasses ? &CodeGenerationTime : 0); + TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : 0); // Make sure IR generation is happy with the module. This is // released by the module provider. @@ -363,10 +373,11 @@ void BackendConsumer::EmitAssembly() { ASTConsumer *clang::CreateBackendConsumer(BackendAction Action, Diagnostic &Diags, const LangOptions &LangOpts, - const CompileOptions &CompileOpts, + const CodeGenOptions &CodeGenOpts, + const TargetOptions &TargetOpts, const std::string& InFile, llvm::raw_ostream* OS, LLVMContext& C) { - return new BackendConsumer(Action, Diags, LangOpts, CompileOpts, - InFile, OS, C); + return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts, + TargetOpts, InFile, OS, C); } diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index e3ec78627da0..3f0f43099c69 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -6,17 +6,21 @@ add_clang_library(clangFrontend AnalysisConsumer.cpp Backend.cpp CacheTokens.cpp + CompilerInstance.cpp + CompilerInvocation.cpp DeclXML.cpp DependencyFile.cpp DiagChecker.cpp DocumentXML.cpp FixItRewriter.cpp + FrontendAction.cpp + FrontendActions.cpp + FrontendOptions.cpp GeneratePCH.cpp HTMLDiagnostics.cpp HTMLPrint.cpp InitHeaderSearch.cpp InitPreprocessor.cpp - ManagerRegistry.cpp PCHReader.cpp PCHReaderDecl.cpp PCHReaderStmt.cpp @@ -34,6 +38,7 @@ add_clang_library(clangFrontend TextDiagnosticBuffer.cpp TextDiagnosticPrinter.cpp TypeXML.cpp + VerifyDiagnosticsClient.cpp Warnings.cpp ) diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp new file mode 100644 index 000000000000..0365761c840e --- /dev/null +++ b/lib/Frontend/CompilerInstance.cpp @@ -0,0 +1,403 @@ +//===--- CompilerInstance.cpp ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/CompilerInstance.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PTHManager.h" +#include "clang/Frontend/ChainedDiagnosticClient.h" +#include "clang/Frontend/PCHReader.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/Utils.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LLVMContext.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +using namespace clang; + +CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext, + bool _OwnsLLVMContext) + : LLVMContext(_LLVMContext), + OwnsLLVMContext(_OwnsLLVMContext) { + } + +CompilerInstance::~CompilerInstance() { + if (OwnsLLVMContext) + delete LLVMContext; +} + +void CompilerInstance::setDiagnostics(Diagnostic *Value) { + Diagnostics.reset(Value); +} + +void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) { + DiagClient.reset(Value); +} + +void CompilerInstance::setTarget(TargetInfo *Value) { + Target.reset(Value); +} + +void CompilerInstance::setFileManager(FileManager *Value) { + FileMgr.reset(Value); +} + +void CompilerInstance::setSourceManager(SourceManager *Value) { + SourceMgr.reset(Value); +} + +void CompilerInstance::setPreprocessor(Preprocessor *Value) { + PP.reset(Value); +} + +void CompilerInstance::setASTContext(ASTContext *Value) { + Context.reset(Value); +} + +void CompilerInstance::setASTConsumer(ASTConsumer *Value) { + Consumer.reset(Value); +} + +void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { + CompletionConsumer.reset(Value); +} + +// Diagnostics + +static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, + unsigned argc, char **argv, + llvm::OwningPtr<DiagnosticClient> &DiagClient) { + std::string ErrorInfo; + llvm::raw_ostream *OS = + new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) { + // FIXME: Do not fail like this. + llvm::errs() << "error opening -dump-build-information file '" + << DiagOpts.DumpBuildInformation << "', option ignored!\n"; + delete OS; + return; + } + + (*OS) << "clang-cc command line arguments: "; + for (unsigned i = 0; i != argc; ++i) + (*OS) << argv[i] << ' '; + (*OS) << '\n'; + + // Chain in a diagnostic client which will log the diagnostics. + DiagnosticClient *Logger = + new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true); + DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger)); +} + +void CompilerInstance::createDiagnostics(int Argc, char **Argv) { + Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv)); + + if (Diagnostics) + DiagClient.reset(Diagnostics->getClient()); +} + +Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, + int Argc, char **Argv) { + llvm::OwningPtr<Diagnostic> Diags(new Diagnostic()); + + // Create the diagnostic client for reporting errors or for + // implementing -verify. + llvm::OwningPtr<DiagnosticClient> DiagClient( + new TextDiagnosticPrinter(llvm::errs(), Opts)); + + // Chain in -verify checker, if requested. + if (Opts.VerifyDiagnostics) + DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take())); + + if (!Opts.DumpBuildInformation.empty()) + SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient); + + // Configure our handling of diagnostics. + Diags->setClient(DiagClient.take()); + if (ProcessWarningOptions(*Diags, Opts)) + return 0; + + return Diags.take(); +} + +// File Manager + +void CompilerInstance::createFileManager() { + FileMgr.reset(new FileManager()); +} + +// Source Manager + +void CompilerInstance::createSourceManager() { + SourceMgr.reset(new SourceManager()); +} + +// Preprocessor + +void CompilerInstance::createPreprocessor() { + PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), + getPreprocessorOpts(), getHeaderSearchOpts(), + getDependencyOutputOpts(), getTarget(), + getSourceManager(), getFileManager())); +} + +Preprocessor * +CompilerInstance::createPreprocessor(Diagnostic &Diags, + const LangOptions &LangInfo, + const PreprocessorOptions &PPOpts, + const HeaderSearchOptions &HSOpts, + const DependencyOutputOptions &DepOpts, + const TargetInfo &Target, + SourceManager &SourceMgr, + FileManager &FileMgr) { + // Create a PTH manager if we are using some form of a token cache. + PTHManager *PTHMgr = 0; + if (!PPOpts.TokenCache.empty()) + PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); + + // FIXME: Don't fail like this. + if (Diags.hasErrorOccurred()) + exit(1); + + // Create the Preprocessor. + HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); + Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, + SourceMgr, *HeaderInfo, PTHMgr, + /*OwnsHeaderSearch=*/true); + + // Note that this is different then passing PTHMgr to Preprocessor's ctor. + // That argument is used as the IdentifierInfoLookup argument to + // IdentifierTable's ctor. + if (PTHMgr) { + PTHMgr->setPreprocessor(PP); + PP->setPTHManager(PTHMgr); + } + + InitializePreprocessor(*PP, PPOpts, HSOpts); + + // Handle generating dependencies, if requested. + if (!DepOpts.OutputFile.empty()) + AttachDependencyFileGen(*PP, DepOpts); + + return PP; +} + +// ASTContext + +void CompilerInstance::createASTContext() { + Preprocessor &PP = getPreprocessor(); + Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), + getTarget(), PP.getIdentifierTable(), + PP.getSelectorTable(), PP.getBuiltinInfo(), + /*FreeMemory=*/ !getFrontendOpts().DisableFree, + /*size_reserve=*/ 0)); +} + +// ExternalASTSource + +void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) { + llvm::OwningPtr<ExternalASTSource> Source; + Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, + getPreprocessor(), getASTContext())); + getASTContext().setExternalSource(Source); +} + +ExternalASTSource * +CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, + const std::string &Sysroot, + Preprocessor &PP, + ASTContext &Context) { + llvm::OwningPtr<PCHReader> Reader; + Reader.reset(new PCHReader(PP, &Context, + Sysroot.empty() ? 0 : Sysroot.c_str())); + + switch (Reader->ReadPCH(Path)) { + case PCHReader::Success: + // Set the predefines buffer as suggested by the PCH reader. Typically, the + // predefines buffer will be empty. + PP.setPredefines(Reader->getSuggestedPredefines()); + return Reader.take(); + + case PCHReader::Failure: + // Unrecoverable failure: don't even try to process the input file. + break; + + case PCHReader::IgnorePCH: + // No suitable PCH file could be found. Return an error. + break; + } + + return 0; +} + +// Code Completion + +void CompilerInstance::createCodeCompletionConsumer() { + const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; + CompletionConsumer.reset( + createCodeCompletionConsumer(getPreprocessor(), + Loc.FileName, Loc.Line, Loc.Column, + getFrontendOpts().DebugCodeCompletionPrinter, + getFrontendOpts().ShowMacrosInCodeCompletion, + llvm::outs())); +} + +CodeCompleteConsumer * +CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, + const std::string &Filename, + unsigned Line, + unsigned Column, + bool UseDebugPrinter, + bool ShowMacros, + llvm::raw_ostream &OS) { + // Tell the source manager to chop off the given file at a specific + // line and column. + const FileEntry *Entry = PP.getFileManager().getFile(Filename); + if (!Entry) { + PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) + << Filename; + return 0; + } + + // Truncate the named file at the given line/column. + PP.getSourceManager().truncateFileAt(Entry, Line, Column); + + // Set up the creation routine for code-completion. + if (UseDebugPrinter) + return new PrintingCodeCompleteConsumer(ShowMacros, OS); + else + return new CIndexCodeCompleteConsumer(ShowMacros, OS); +} + +// Output Files + +void CompilerInstance::addOutputFile(llvm::StringRef Path, + llvm::raw_ostream *OS) { + assert(OS && "Attempt to add empty stream to output list!"); + OutputFiles.push_back(std::make_pair(Path, OS)); +} + +void CompilerInstance::ClearOutputFiles(bool EraseFiles) { + for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator + it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { + delete it->second; + if (EraseFiles && !it->first.empty()) + llvm::sys::Path(it->first).eraseFromDisk(); + } + OutputFiles.clear(); +} + +llvm::raw_fd_ostream * +CompilerInstance::createDefaultOutputFile(bool Binary, + llvm::StringRef InFile, + llvm::StringRef Extension) { + return createOutputFile(getFrontendOpts().OutputFile, Binary, + InFile, Extension); +} + +llvm::raw_fd_ostream * +CompilerInstance::createOutputFile(llvm::StringRef OutputPath, + bool Binary, + llvm::StringRef InFile, + llvm::StringRef Extension) { + std::string Error, OutputPathName; + llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, + InFile, Extension, + &OutputPathName); + if (!OS) { + // FIXME: Don't fail this way. + llvm::errs() << "ERROR: " << Error << "\n"; + ::exit(1); + } + + // Add the output file -- but don't try to remove "-", since this means we are + // using stdin. + addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS); + + return OS; +} + +llvm::raw_fd_ostream * +CompilerInstance::createOutputFile(llvm::StringRef OutputPath, + std::string &Error, + bool Binary, + llvm::StringRef InFile, + llvm::StringRef Extension, + std::string *ResultPathName) { + std::string OutFile; + if (!OutputPath.empty()) { + OutFile = OutputPath; + } else if (InFile == "-") { + OutFile = "-"; + } else if (!Extension.empty()) { + llvm::sys::Path Path(InFile); + Path.eraseSuffix(); + Path.appendSuffix(Extension); + OutFile = Path.str(); + } else { + OutFile = "-"; + } + + llvm::raw_fd_ostream *OS = + new llvm::raw_fd_ostream(OutFile.c_str(), Error, + (Binary ? llvm::raw_fd_ostream::F_Binary : 0)); + if (!OS) + return 0; + + if (ResultPathName) + *ResultPathName = OutFile; + + return OS; +} + +// Initialization Utilities + +bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { + return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), + getSourceManager(), getFrontendOpts()); +} + +bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, + Diagnostic &Diags, + FileManager &FileMgr, + SourceManager &SourceMgr, + const FrontendOptions &Opts) { + // Figure out where to get and map in the main file. + if (Opts.EmptyInputOnly) { + const char *EmptyStr = ""; + llvm::MemoryBuffer *SB = + llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>"); + SourceMgr.createMainFileIDForMemBuffer(SB); + } else if (InputFile != "-") { + const FileEntry *File = FileMgr.getFile(InputFile); + if (File) SourceMgr.createMainFileID(File, SourceLocation()); + if (SourceMgr.getMainFileID().isInvalid()) { + Diags.Report(diag::err_fe_error_reading) << InputFile; + return false; + } + } else { + llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN(); + SourceMgr.createMainFileIDForMemBuffer(SB); + if (SourceMgr.getMainFileID().isInvalid()) { + Diags.Report(diag::err_fe_error_reading_stdin); + return false; + } + } + + return true; +} diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp new file mode 100644 index 000000000000..ed6d0b71a51b --- /dev/null +++ b/lib/Frontend/CompilerInvocation.cpp @@ -0,0 +1,548 @@ +//===--- CompilerInvocation.cpp -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/CompilerInvocation.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" +using namespace clang; + +void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, + const llvm::SmallVectorImpl<llvm::StringRef> &Args) { + llvm::llvm_report_error("FIXME: Not yet implemented!"); +} + +static const char *getAnalysisName(Analyses Kind) { + switch (Kind) { + default: + llvm::llvm_unreachable("Unknown analysis store!"); +#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\ + case NAME: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static const char *getAnalysisStoreName(AnalysisStores Kind) { + switch (Kind) { + default: + llvm::llvm_unreachable("Unknown analysis store!"); +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ + case NAME##Model: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { + switch (Kind) { + default: + llvm::llvm_unreachable("Unknown analysis constraints!"); +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ + case NAME##Model: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { + switch (Kind) { + default: + llvm::llvm_unreachable("Unknown analysis client!"); +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \ + case PD_##NAME: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, + std::vector<std::string> &Res) { + for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i) + Res.push_back(getAnalysisName(Opts.AnalysisList[i])); + if (Opts.AnalysisStoreOpt != BasicStoreModel) { + Res.push_back("-analyzer-store"); + Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt)); + } + if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) { + Res.push_back("-analyzer-constraints"); + Res.push_back(getAnalysisConstraintName(Opts.AnalysisConstraintsOpt)); + } + if (Opts.AnalysisDiagOpt != PD_HTML) { + Res.push_back("-analyzer-output"); + Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt)); + } + if (!Opts.AnalyzeSpecificFunction.empty()) { + Res.push_back("-analyze-function"); + Res.push_back(Opts.AnalyzeSpecificFunction); + } + if (Opts.AnalyzeAll) + Res.push_back("-analyzer-opt-analyze-headers"); + if (Opts.AnalyzerDisplayProgress) + Res.push_back("-analyzer-display-progress"); + if (Opts.EagerlyAssume) + Res.push_back("-analyzer-eagerly-assume"); + if (Opts.PurgeDead) + Res.push_back("-analyzer-purge-dead"); + if (Opts.TrimGraph) + Res.push_back("-trim-egraph"); + if (Opts.VisualizeEGDot) + Res.push_back("-analyzer-viz-egraph-graphviz"); + if (Opts.VisualizeEGDot) + Res.push_back("-analyzer-viz-egraph-ubigraph"); + if (Opts.EnableExperimentalChecks) + Res.push_back("-analyzer-experimental-checks"); + if (Opts.EnableExperimentalInternalChecks) + Res.push_back("-analyzer-experimental-internal-checls"); +} + +static void CodeGenOptsToArgs(const CodeGenOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.DebugInfo) + Res.push_back("-g"); + if (Opts.DisableLLVMOpts) + Res.push_back("-disable-llvm-optzns"); + if (Opts.DisableRedZone) + Res.push_back("-disable-red-zone"); + if (!Opts.MergeAllConstants) + Res.push_back("-fno-merge-all-constants"); + // NoCommon is only derived. + if (Opts.NoImplicitFloat) + Res.push_back("-no-implicit-float"); + if (Opts.OptimizeSize) { + assert(Opts.OptimizationLevel == 2 && "Invalid options!"); + Res.push_back("-Os"); + } else if (Opts.OptimizationLevel == 0) + Res.push_back("-O" + Opts.OptimizationLevel); + // SimplifyLibCalls is only derived. + // TimePasses is only derived. + // UnitAtATime is unused. + // UnrollLoops is only derived. + // VerifyModule is only derived. + // Inlining is only derived. +} + +static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.IncludeSystemHeaders) + Res.push_back("-sys-header-deps"); + if (Opts.UsePhonyTargets) + Res.push_back("-MP"); + if (!Opts.OutputFile.empty()) { + Res.push_back("-dependency-file"); + Res.push_back(Opts.OutputFile); + } + for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i) { + Res.push_back("-MT"); + Res.push_back(Opts.Targets[i]); + } +} + +static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.IgnoreWarnings) + Res.push_back("-w"); + if (Opts.NoRewriteMacros) + Res.push_back("-Wno-rewrite-macros"); + if (Opts.Pedantic) + Res.push_back("-pedantic"); + if (Opts.PedanticErrors) + Res.push_back("-pedantic-errors"); + if (!Opts.ShowColumn) + Res.push_back("-fno-show-column"); + if (!Opts.ShowLocation) + Res.push_back("-fno-show-source-location"); + if (!Opts.ShowCarets) + Res.push_back("-fno-caret-diagnostics"); + if (!Opts.ShowFixits) + Res.push_back("-fno-diagnostics-fixit-info"); + if (Opts.ShowSourceRanges) + Res.push_back("-fdiagnostics-print-source-range-info"); + if (Opts.ShowColors) + Res.push_back("-fcolor-diagnostics"); + if (Opts.VerifyDiagnostics) + Res.push_back("-verify"); + if (Opts.ShowOptionNames) + Res.push_back("-fdiagnostics-show-option"); + if (Opts.MessageLength) { + Res.push_back("-fmessage-length"); + Res.push_back(llvm::utostr(Opts.MessageLength)); + } + if (!Opts.DumpBuildInformation.empty()) { + Res.push_back("-dump-build-information"); + Res.push_back(Opts.DumpBuildInformation); + } + for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) + Res.push_back("-W" + Opts.Warnings[i]); +} + +static const char *getInputKindName(FrontendOptions::InputKind Kind) { + switch (Kind) { + case FrontendOptions::IK_None: break; + case FrontendOptions::IK_AST: return "ast"; + case FrontendOptions::IK_Asm: return "assembler-with-cpp"; + case FrontendOptions::IK_C: return "c"; + case FrontendOptions::IK_CXX: return "c++"; + case FrontendOptions::IK_ObjC: return "objective-c"; + case FrontendOptions::IK_ObjCXX: return "objective-c++"; + case FrontendOptions::IK_OpenCL: return "cl"; + case FrontendOptions::IK_PreprocessedC: return "cpp-output"; + case FrontendOptions::IK_PreprocessedCXX: return "c++-cpp-output"; + case FrontendOptions::IK_PreprocessedObjC: return "objective-c-cpp-output"; + case FrontendOptions::IK_PreprocessedObjCXX: return "objective-c++-cpp-output"; + } + + llvm::llvm_unreachable("Unexpected language kind!"); + return 0; +} + +static const char *getActionName(frontend::ActionKind Kind) { + switch (Kind) { + case frontend::PluginAction: + case frontend::InheritanceView: + llvm::llvm_unreachable("Invalid kind!"); + + case frontend::ASTDump: return "-ast-dump"; + case frontend::ASTPrint: return "-ast-print"; + case frontend::ASTPrintXML: return "-ast-print-xml"; + case frontend::ASTView: return "-ast-view"; + case frontend::DumpRawTokens: return "-dump-raw-tokens"; + case frontend::DumpRecordLayouts: return "-dump-record-layouts"; + case frontend::DumpTokens: return "-dump-tokens"; + case frontend::EmitAssembly: return "-S"; + case frontend::EmitBC: return "-emit-llvm-bc"; + case frontend::EmitHTML: return "-emit-html"; + case frontend::EmitLLVM: return "-emit-llvm"; + case frontend::EmitLLVMOnly: return "-emit-llvm-only"; + case frontend::FixIt: return "-fixit"; + case frontend::GeneratePCH: return "-emit-pch"; + case frontend::GeneratePTH: return "-emit-pth"; + case frontend::ParseNoop: return "-parse-noop"; + case frontend::ParsePrintCallbacks: return "-parse-print-callbacks"; + case frontend::ParseSyntaxOnly: return "-fsyntax-only"; + case frontend::PrintDeclContext: return "-print-decl-contexts"; + case frontend::PrintPreprocessedInput: return "-E"; + case frontend::RewriteBlocks: return "-rewrite-blocks"; + case frontend::RewriteMacros: return "-rewrite-macros"; + case frontend::RewriteObjC: return "-rewrite-objc"; + case frontend::RewriteTest: return "-rewrite-test"; + case frontend::RunAnalysis: return "-analyze"; + case frontend::RunPreprocessorOnly: return "-Eonly"; + } + + llvm::llvm_unreachable("Unexpected language kind!"); + return 0; +} + +static void FrontendOptsToArgs(const FrontendOptions &Opts, + std::vector<std::string> &Res) { + if (!Opts.DebugCodeCompletionPrinter) + Res.push_back("-code-completion-debug-printer=0"); + if (Opts.DisableFree) + Res.push_back("-disable-free"); + if (Opts.EmptyInputOnly) + Res.push_back("-empty-input-only"); + if (Opts.RelocatablePCH) + Res.push_back("-relocatable-pch"); + if (Opts.ShowMacrosInCodeCompletion) + Res.push_back("-code-completion-macros"); + if (Opts.ShowStats) + Res.push_back("-stats"); + if (Opts.ShowTimers) + Res.push_back("-ftime-report"); + + bool NeedLang = false; + for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) + if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].second) != + Opts.Inputs[i].first) + NeedLang = true; + if (NeedLang) { + Res.push_back("-x"); + Res.push_back(getInputKindName(Opts.Inputs[0].first)); + } + for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) { + assert((!NeedLang || Opts.Inputs[i].first == Opts.Inputs[0].first) && + "Unable to represent this input vector!"); + Res.push_back(Opts.Inputs[i].second); + } + + if (!Opts.OutputFile.empty()) { + Res.push_back("-o"); + Res.push_back(Opts.OutputFile); + } + if (!Opts.ViewClassInheritance.empty()) { + Res.push_back("-cxx-inheritance-view"); + Res.push_back(Opts.ViewClassInheritance); + } + for (unsigned i = 0, e = Opts.FixItLocations.size(); i != e; ++i) { + Res.push_back("-fixit-at"); + Res.push_back(Opts.FixItLocations[i].FileName + ":" + + llvm::utostr(Opts.FixItLocations[i].Line) + ":" + + llvm::utostr(Opts.FixItLocations[i].Column)); + } + if (!Opts.CodeCompletionAt.FileName.empty()) { + Res.push_back("-code-completion-at"); + Res.push_back(Opts.CodeCompletionAt.FileName + ":" + + llvm::utostr(Opts.CodeCompletionAt.Line) + ":" + + llvm::utostr(Opts.CodeCompletionAt.Column)); + } + if (Opts.ProgramAction != frontend::InheritanceView && + Opts.ProgramAction != frontend::PluginAction) + Res.push_back(getActionName(Opts.ProgramAction)); + if (!Opts.ActionName.empty()) { + Res.push_back("-plugin"); + Res.push_back(Opts.ActionName); + } +} + +static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.Sysroot.empty()) { + Res.push_back("-isysroot"); + Res.push_back(Opts.Sysroot); + } + + /// User specified include entries. + for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) { + const HeaderSearchOptions::Entry &E = Opts.UserEntries[i]; + if (E.IsFramework && (E.Group != frontend::Angled || E.IsUserSupplied)) + llvm::llvm_report_error("Invalid option set!"); + if (E.IsUserSupplied) { + if (E.Group == frontend::After) { + Res.push_back("-idirafter"); + } else if (E.Group == frontend::Quoted) { + Res.push_back("-iquoted"); + } else if (E.Group == frontend::System) { + Res.push_back("-isystem"); + } else { + assert(E.Group == frontend::Angled && "Invalid group!"); + Res.push_back(E.IsFramework ? "-F" : "-I"); + } + } else { + if (E.Group != frontend::Angled && E.Group != frontend::System) + llvm::llvm_report_error("Invalid option set!"); + Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" : + "-iwithprefix"); + } + Res.push_back(E.Path); + } + + if (!Opts.EnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::llvm_report_error("Not yet implemented!"); + } + if (!Opts.CEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::llvm_report_error("Not yet implemented!"); + } + if (!Opts.ObjCEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::llvm_report_error("Not yet implemented!"); + } + if (!Opts.CXXEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::llvm_report_error("Not yet implemented!"); + } + if (!Opts.ObjCXXEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::llvm_report_error("Not yet implemented!"); + } + if (!Opts.BuiltinIncludePath.empty()) { + // FIXME: Provide an option for this, and move to driver. + } + if (!Opts.UseStandardIncludes) + Res.push_back("-nostdinc"); + if (Opts.Verbose) + Res.push_back("-v"); +} + +static void LangOptsToArgs(const LangOptions &Opts, + std::vector<std::string> &Res) { + LangOptions DefaultLangOpts; + + // FIXME: Need to set -std to get all the implicit options. + + // FIXME: We want to only pass options relative to the defaults, which + // requires constructing a target. :( + // + // It would be better to push the all target specific choices into the driver, + // so that everything below that was more uniform. + + if (Opts.Trigraphs) + Res.push_back("-trigraphs"); + // Implicit based on the input kind: + // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL + // Implicit based on the input language standard: + // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode + if (Opts.DollarIdents) + Res.push_back("-fdollars-in-identifiers"); + if (Opts.Microsoft) + Res.push_back("-fms-extensions=1"); + if (Opts.ObjCNonFragileABI) + Res.push_back("-fobjc-nonfragile-abi"); + // NoInline is implicit. + if (!Opts.CXXOperatorNames) + Res.push_back("-fno-operator-names"); + if (Opts.PascalStrings) + Res.push_back("-fpascal-strings"); + if (Opts.WritableStrings) + Res.push_back("-fwritable-strings"); + if (!Opts.LaxVectorConversions) + Res.push_back("-fno-lax-vector-conversions"); + if (Opts.AltiVec) + Res.push_back("-faltivec"); + Res.push_back("-fexceptions"); + Res.push_back(Opts.Exceptions ? "1" : "0"); + Res.push_back("-frtti"); + Res.push_back(Opts.Rtti ? "1" : "0"); + if (!Opts.NeXTRuntime) + Res.push_back("-fgnu-runtime"); + if (Opts.Freestanding) + Res.push_back("-ffreestanding"); + if (Opts.NoBuiltin) + Res.push_back("-fno-builtin"); + if (Opts.ThreadsafeStatics) + llvm::llvm_report_error("FIXME: Not yet implemented!"); + if (Opts.POSIXThreads) + Res.push_back("-pthread"); + if (Opts.Blocks) + Res.push_back("-fblocks=1"); + if (Opts.EmitAllDecls) + Res.push_back("-femit-all-decls"); + if (!Opts.MathErrno) + Res.push_back("-fmath-errno=0"); + if (Opts.OverflowChecking) + Res.push_back("-ftrapv"); + if (Opts.HeinousExtensions) + Res.push_back("-fheinous-gnu-extensions"); + // Optimize is implicit. + // OptimizeSize is implicit. + if (Opts.Static) + Res.push_back("-static-define"); + if (Opts.PICLevel) { + Res.push_back("-pic-level"); + Res.push_back(llvm::utostr(Opts.PICLevel)); + } + if (Opts.ObjCGCBitmapPrint) + Res.push_back("-print-ivar-layout"); + Res.push_back("-faccess-control"); + Res.push_back(Opts.AccessControl ? "1" : "0"); + Res.push_back("-fsigned-char"); + Res.push_back(Opts.CharIsSigned ? "1" : "0"); + Res.push_back("-fshort-wchar"); + Res.push_back(Opts.ShortWChar ? "1" : "0"); + if (!Opts.ElideConstructors) + Res.push_back("-fno-elide-constructors"); + if (Opts.getGCMode() != LangOptions::NonGC) { + if (Opts.getGCMode() == LangOptions::HybridGC) { + Res.push_back("-fobjc-gc"); + } else { + assert(Opts.getGCMode() == LangOptions::GCOnly && "Invalid GC mode!"); + Res.push_back("-fobjc-gc-only"); + } + } + if (Opts.getVisibilityMode() != LangOptions::Default) { + Res.push_back("-fvisibility"); + if (Opts.getVisibilityMode() == LangOptions::Hidden) { + Res.push_back("default"); + } else { + assert(Opts.getVisibilityMode() == LangOptions::Protected && + "Invalid visibility!"); + Res.push_back("protected"); + } + } + if (Opts.getStackProtectorMode() != 0) { + Res.push_back("-stack-protector"); + Res.push_back(llvm::utostr(Opts.getStackProtectorMode())); + } + if (Opts.getMainFileName()) { + Res.push_back("-main-file-name"); + Res.push_back(Opts.getMainFileName()); + } + if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) { + Res.push_back("-ftemplate-depth"); + Res.push_back(llvm::utostr(Opts.InstantiationDepth)); + } + if (Opts.ObjCConstantStringClass) { + Res.push_back("-fconstant-string-class"); + Res.push_back(Opts.ObjCConstantStringClass); + } +} + +static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, + std::vector<std::string> &Res) { + for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i) + Res.push_back((Opts.Macros[i].second ? "-U" : "-D") + Opts.Macros[i].first); + for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) { + Res.push_back("-include"); + Res.push_back(Opts.Includes[i]); + } + for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) { + Res.push_back("-imacros"); + Res.push_back(Opts.Includes[i]); + } + if (!Opts.UsePredefines) + Res.push_back("-undef"); + if (!Opts.ImplicitPCHInclude.empty()) { + Res.push_back("-implicit-pch-include"); + Res.push_back(Opts.ImplicitPCHInclude); + } + if (!Opts.ImplicitPTHInclude.empty()) { + Res.push_back("-implicit-pth-include"); + Res.push_back(Opts.ImplicitPTHInclude); + } + if (!Opts.TokenCache.empty()) { + Res.push_back("-token-cache"); + Res.push_back(Opts.TokenCache); + } +} + +static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, + std::vector<std::string> &Res) { + if (!Opts.ShowCPP && !Opts.ShowMacros) + llvm::llvm_report_error("Invalid option combination!"); + + if (Opts.ShowCPP && Opts.ShowMacros) + Res.push_back("-dD"); + else if (!Opts.ShowCPP && Opts.ShowMacros) + Res.push_back("-dM"); + + if (!Opts.ShowLineMarkers) + Res.push_back("-P"); + if (Opts.ShowComments) + Res.push_back("-C"); + if (Opts.ShowMacroComments) + Res.push_back("-CC"); +} + +static void TargetOptsToArgs(const TargetOptions &Opts, + std::vector<std::string> &Res) { + Res.push_back("-triple"); + Res.push_back(Opts.Triple); + if (!Opts.CPU.empty()) { + Res.push_back("-target-cpu"); + Res.push_back(Opts.CPU); + } + if (!Opts.ABI.empty()) { + Res.push_back("-target-abi"); + Res.push_back(Opts.ABI); + } + for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) { + Res.push_back("-target-feature"); + Res.push_back(Opts.Features[i]); + } +} + +void CompilerInvocation::toArgs(std::vector<std::string> &Res) { + AnalyzerOptsToArgs(getAnalyzerOpts(), Res); + CodeGenOptsToArgs(getCodeGenOpts(), Res); + DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res); + DiagnosticOptsToArgs(getDiagnosticOpts(), Res); + FrontendOptsToArgs(getFrontendOpts(), Res); + HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res); + LangOptsToArgs(getLangOpts(), Res); + PreprocessorOptsToArgs(getPreprocessorOpts(), Res); + PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res); + TargetOptsToArgs(getTargetOpts(), Res); +} diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index 81d1179f28e3..c7f93595e1ea 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -12,12 +12,14 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/Utils.h" -#include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/PPCallbacks.h" -#include "clang/Lex/DirectoryLookup.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/DependencyOutputOptions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/DirectoryLookup.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" @@ -42,11 +44,10 @@ private: public: DependencyFileCallback(const Preprocessor *_PP, llvm::raw_ostream *_OS, - const std::vector<std::string> &_Targets, - bool _IncludeSystemHeaders, - bool _PhonyTarget) - : PP(_PP), Targets(_Targets), OS(_OS), - IncludeSystemHeaders(_IncludeSystemHeaders), PhonyTarget(_PhonyTarget) {} + const DependencyOutputOptions &Opts) + : PP(_PP), Targets(Opts.Targets), OS(_OS), + IncludeSystemHeaders(Opts.IncludeSystemHeaders), + PhonyTarget(Opts.UsePhonyTargets) {} ~DependencyFileCallback() { OutputDependencyFile(); @@ -59,18 +60,23 @@ public: }; } +void clang::AttachDependencyFileGen(Preprocessor &PP, + const DependencyOutputOptions &Opts) { + if (Opts.Targets.empty()) { + PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT); + return; + } + std::string Err; + llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err)); + if (!Err.empty()) { + PP.getDiagnostics().Report(diag::err_fe_error_opening) + << Opts.OutputFile << Err; + return; + } -void clang::AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS, - std::vector<std::string> &Targets, - bool IncludeSystemHeaders, - bool PhonyTarget) { - assert(!Targets.empty() && "Target required for dependency generation"); - - DependencyFileCallback *PPDep = - new DependencyFileCallback(PP, OS, Targets, IncludeSystemHeaders, - PhonyTarget); - PP->setPPCallbacks(PPDep); + assert(!PP.getPPCallbacks() && "Preprocessor callbacks already registered!"); + PP.setPPCallbacks(new DependencyFileCallback(&PP, OS, Opts)); } /// FileMatchesDepCriteria - Determine whether the given Filename should be diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp index d92d4cb7b8de..0263c30bfd57 100644 --- a/lib/Frontend/DocumentXML.cpp +++ b/lib/Frontend/DocumentXML.cpp @@ -135,7 +135,7 @@ void DocumentXML::finalize() { for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end(); i != e; ++i) { - if (i->first.hasQualifiers()) { + if (i->first.hasLocalQualifiers()) { writeTypeToXML(i->first); addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); toParent(); @@ -205,7 +205,7 @@ void DocumentXML::addTypeRecursively(const QualType& pType) { addTypeRecursively(pType.getTypePtr()); // beautifier: a non-qualified type shall be transparent - if (!pType.hasQualifiers()) + if (!pType.hasLocalQualifiers()) { Types[pType] = BasicTypes[pType.getTypePtr()]; } diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp new file mode 100644 index 000000000000..ff63a0dab5f9 --- /dev/null +++ b/lib/Frontend/FrontendAction.cpp @@ -0,0 +1,225 @@ +//===--- FrontendAction.cpp -----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendAction.h" +#include "clang/AST/ASTContext.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Sema/ParseAST.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +FrontendAction::FrontendAction() : Instance(0), CurrentTimer(0) {} + +FrontendAction::~FrontendAction() {} + +void FrontendAction::setCurrentFile(llvm::StringRef Value, ASTUnit *AST) { + CurrentFile = Value; + CurrentASTUnit.reset(AST); +} + +bool FrontendAction::BeginSourceFile(CompilerInstance &CI, + llvm::StringRef Filename, + bool IsAST) { + assert(!Instance && "Already processing a source file!"); + assert(!Filename.empty() && "Unexpected empty filename!"); + setCurrentFile(Filename); + setCompilerInstance(&CI); + + // AST files follow a very different path, since they share objects via the + // AST unit. + if (IsAST) { + assert(!usesPreprocessorOnly() && + "Attempt to pass AST file to preprocessor only action!"); + assert(hasASTSupport() && "This action does not have AST support!"); + + std::string Error; + ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, &Error); + if (!AST) { + CI.getDiagnostics().Report(diag::err_fe_invalid_ast_file) << Error; + goto failure; + } + + setCurrentFile(Filename, AST); + + // Set the shared objects, these are reset when we finish processing the + // file, otherwise the CompilerInstance will happily destroy them. + CI.setFileManager(&AST->getFileManager()); + CI.setSourceManager(&AST->getSourceManager()); + CI.setPreprocessor(&AST->getPreprocessor()); + CI.setASTContext(&AST->getASTContext()); + + // Initialize the action. + if (!BeginSourceFileAction(CI, Filename)) + goto failure; + + /// Create the AST consumer. + CI.setASTConsumer(CreateASTConsumer(CI, Filename)); + if (!CI.hasASTConsumer()) + goto failure; + + return true; + } + + // Inform the diagnostic client we are processing a source file. + CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), + &CI.getPreprocessor()); + + // Initialize the action. + if (!BeginSourceFileAction(CI, Filename)) + goto failure; + + /// Create the AST context and consumer unless this is a preprocessor only + /// action. + if (!usesPreprocessorOnly()) { + CI.createASTContext(); + CI.setASTConsumer(CreateASTConsumer(CI, Filename)); + if (!CI.hasASTConsumer()) + goto failure; + + /// Use PCH? + if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + assert(hasPCHSupport() && "This action does not have PCH support!"); + CI.createPCHExternalASTSource( + CI.getPreprocessorOpts().ImplicitPCHInclude); + if (!CI.getASTContext().getExternalSource()) + goto failure; + } + } + + // Initialize builtin info as long as we aren't using an external AST + // source. + if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { + Preprocessor &PP = CI.getPreprocessor(); + PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), + PP.getLangOptions().NoBuiltin); + } + + return true; + + // If we failed, reset state since the client will not end up calling the + // matching EndSourceFile(). + failure: + if (isCurrentFileAST()) { + CI.takeASTContext(); + CI.takePreprocessor(); + CI.takeSourceManager(); + CI.takeFileManager(); + } + + CI.getDiagnosticClient().EndSourceFile(); + setCurrentFile(""); + setCompilerInstance(0); + return false; +} + +void FrontendAction::Execute() { + CompilerInstance &CI = getCompilerInstance(); + + // Initialize the main file entry. This needs to be delayed until after PCH + // has loaded. + if (isCurrentFileAST()) { + // Set the main file ID to an empty file. + // + // FIXME: We probably shouldn't need this, but for now this is the + // simplest way to reuse the logic in ParseAST. + const char *EmptyStr = ""; + llvm::MemoryBuffer *SB = + llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<dummy input>"); + CI.getSourceManager().createMainFileIDForMemBuffer(SB); + } else { + if (!CI.InitializeSourceManager(getCurrentFile())) + return; + } + + llvm::TimeRegion Timer(CurrentTimer); + ExecuteAction(); +} + +void FrontendAction::EndSourceFile() { + CompilerInstance &CI = getCompilerInstance(); + + // Finalize the action. + EndSourceFileAction(); + + // Release the consumer and the AST, in that order since the consumer may + // perform actions in its destructor which require the context. + // + // FIXME: There is more per-file stuff we could just drop here? + if (CI.getFrontendOpts().DisableFree) { + CI.takeASTConsumer(); + if (!isCurrentFileAST()) + CI.takeASTContext(); + } else { + CI.setASTConsumer(0); + if (!isCurrentFileAST()) + CI.setASTContext(0); + } + + if (CI.getFrontendOpts().ShowStats) { + llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n"; + CI.getPreprocessor().PrintStats(); + CI.getPreprocessor().getIdentifierTable().PrintStats(); + CI.getPreprocessor().getHeaderSearchInfo().PrintStats(); + CI.getSourceManager().PrintStats(); + llvm::errs() << "\n"; + } + + // Cleanup the output streams, and erase the output files if we encountered + // an error. + CI.ClearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors()); + + // Inform the diagnostic client we are done with this source file. + CI.getDiagnosticClient().EndSourceFile(); + + if (isCurrentFileAST()) { + CI.takeASTContext(); + CI.takePreprocessor(); + CI.takeSourceManager(); + CI.takeFileManager(); + } + + setCompilerInstance(0); + setCurrentFile(""); +} + +//===----------------------------------------------------------------------===// +// Utility Actions +//===----------------------------------------------------------------------===// + +void ASTFrontendAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + + // FIXME: Move the truncation aspect of this into Sema, we delayed this till + // here so the source manager would be initialized. + if (hasCodeCompletionSupport() && + !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) + CI.createCodeCompletionConsumer(); + + // Use a code completion consumer? + CodeCompleteConsumer *CompletionConsumer = 0; + if (CI.hasCodeCompletionConsumer()) + CompletionConsumer = &CI.getCodeCompletionConsumer(); + + ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(), + CI.getFrontendOpts().ShowStats, + usesCompleteTranslationUnit(), CompletionConsumer); +} + +ASTConsumer * +PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + llvm::llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); +} diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp new file mode 100644 index 000000000000..7a7537bce40f --- /dev/null +++ b/lib/Frontend/FrontendActions.cpp @@ -0,0 +1,281 @@ +//===--- FrontendActions.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendActions.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/Parser.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/AnalysisConsumer.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FixItRewriter.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/Utils.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// AST Consumer Actions +//===----------------------------------------------------------------------===// + +ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateAnalysisConsumer(CI.getPreprocessor(), + CI.getFrontendOpts().OutputFile, + CI.getAnalyzerOpts()); +} + +ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateASTPrinter(CI.createDefaultOutputFile(false, InFile)); +} + +ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateASTPrinterXML(CI.createDefaultOutputFile(false, InFile, + "xml")); +} + +ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateASTDumper(); +} + +ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateASTViewer(); +} + +ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateDeclContextPrinter(); +} + +ASTConsumer *DumpRecordAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateRecordLayoutDumper(); +} + +ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; + if (CI.getFrontendOpts().RelocatablePCH && + Sysroot.empty()) { + CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot); + return 0; + } + + llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); + if (CI.getFrontendOpts().RelocatablePCH) + return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str()); + + return CreatePCHGenerator(CI.getPreprocessor(), OS); +} + +ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateHTMLPrinter(CI.createDefaultOutputFile(false, InFile), + CI.getPreprocessor()); +} + +ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance); +} + +FixItAction::FixItAction() {} +FixItAction::~FixItAction() {} + +ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new ASTConsumer(); +} + +/// AddFixItLocations - Add any individual user specified "fix-it" locations, +/// and return true on success. +static bool AddFixItLocations(CompilerInstance &CI, + FixItRewriter &FixItRewrite) { + const std::vector<ParsedSourceLocation> &Locs = + CI.getFrontendOpts().FixItLocations; + for (unsigned i = 0, e = Locs.size(); i != e; ++i) { + const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName); + if (!File) { + CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file) + << Locs[i].FileName; + return false; + } + + RequestedSourceLocation Requested; + Requested.File = File; + Requested.Line = Locs[i].Line; + Requested.Column = Locs[i].Column; + FixItRewrite.addFixItLocation(Requested); + } + + return true; +} + +bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, + llvm::StringRef Filename) { + Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), + CI.getLangOpts())); + if (!AddFixItLocations(CI, *Rewriter)) + return false; + + return true; +} + +void FixItAction::EndSourceFileAction() { + const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); + Rewriter->WriteFixedFile(getCurrentFile(), FEOpts.OutputFile); +} + +ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateObjCRewriter(InFile, + CI.createDefaultOutputFile(true, InFile, "cpp"), + CI.getDiagnostics(), CI.getLangOpts(), + CI.getDiagnosticOpts().NoRewriteMacros); +} + +ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateBlockRewriter(InFile, CI.getDiagnostics(), CI.getLangOpts()); +} + +ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new ASTConsumer(); +} + +CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} + +ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + BackendAction BA = static_cast<BackendAction>(Act); + llvm::OwningPtr<llvm::raw_ostream> OS; + if (BA == Backend_EmitAssembly) + OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); + else if (BA == Backend_EmitLL) + OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); + else if (BA == Backend_EmitBC) + OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); + + return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), + CI.getCodeGenOpts(), CI.getTargetOpts(), InFile, + OS.take(), CI.getLLVMContext()); +} + +EmitAssemblyAction::EmitAssemblyAction() + : CodeGenAction(Backend_EmitAssembly) {} + +EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {} + +EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} + +EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} + +//===----------------------------------------------------------------------===// +// Preprocessor Actions +//===----------------------------------------------------------------------===// + +void DumpRawTokensAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + SourceManager &SM = PP.getSourceManager(); + + // Start lexing the specified input file. + Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions()); + RawLex.SetKeepWhitespaceMode(true); + + Token RawTok; + RawLex.LexFromRawLexer(RawTok); + while (RawTok.isNot(tok::eof)) { + PP.DumpToken(RawTok, true); + fprintf(stderr, "\n"); + RawLex.LexFromRawLexer(RawTok); + } +} + +void DumpTokensAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + // Start preprocessing the specified input file. + Token Tok; + PP.EnterMainSourceFile(); + do { + PP.Lex(Tok); + PP.DumpToken(Tok, true); + fprintf(stderr, "\n"); + } while (Tok.isNot(tok::eof)); +} + +void GeneratePTHAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + if (CI.getFrontendOpts().OutputFile.empty() || + CI.getFrontendOpts().OutputFile == "-") { + // FIXME: Don't fail this way. + // FIXME: Verify that we can actually seek in the given file. + llvm::errs() << "ERROR: PTH requires an seekable file for output!\n"; + ::exit(1); + } + llvm::raw_fd_ostream *OS = + CI.createDefaultOutputFile(true, getCurrentFile()); + CacheTokens(CI.getPreprocessor(), OS); +} + +void ParseOnlyAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + llvm::OwningPtr<Action> PA(new MinimalAction(PP)); + + Parser P(PP, *PA); + PP.EnterMainSourceFile(); + P.ParseTranslationUnit(); +} + +void PreprocessOnlyAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + + Token Tok; + // Start parsing the specified input file. + PP.EnterMainSourceFile(); + do { + PP.Lex(Tok); + } while (Tok.isNot(tok::eof)); +} + +void PrintParseAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS)); + + Parser P(PP, *PA); + PP.EnterMainSourceFile(); + P.ParseTranslationUnit(); +} + +void PrintPreprocessedAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + DoPrintPreprocessedInput(CI.getPreprocessor(), OS, + CI.getPreprocessorOutputOpts()); +} + +void RewriteMacrosAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + RewriteMacrosInInput(CI.getPreprocessor(), OS); +} + +void RewriteTestAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + DoRewriteTest(CI.getPreprocessor(), OS); +} diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp new file mode 100644 index 000000000000..bd916386056b --- /dev/null +++ b/lib/Frontend/FrontendOptions.cpp @@ -0,0 +1,31 @@ +//===--- FrontendOptions.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendOptions.h" +#include "llvm/ADT/StringSwitch.h" +using namespace clang; + +FrontendOptions::InputKind +FrontendOptions::getInputKindForExtension(llvm::StringRef Extension) { + return llvm::StringSwitch<InputKind>(Extension) + .Case("ast", IK_AST) + .Case("c", IK_C) + .Cases("S", "s", IK_Asm) + .Case("i", IK_PreprocessedC) + .Case("ii", IK_PreprocessedCXX) + .Case("m", IK_ObjC) + .Case("mi", IK_PreprocessedObjC) + .Cases("mm", "M", IK_ObjCXX) + .Case("mii", IK_PreprocessedObjCXX) + .Case("C", IK_CXX) + .Cases("C", "cc", "cp", IK_CXX) + .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX) + .Case("cl", IK_OpenCL) + .Default(IK_C); +} diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp index 145d53f3fc6e..3ba7abf38168 100644 --- a/lib/Frontend/HTMLDiagnostics.cpp +++ b/lib/Frontend/HTMLDiagnostics.cpp @@ -109,6 +109,8 @@ HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) ReportDiag(*D, FilesMade); delete D; } + + BatchedDiags.clear(); } void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index c0b4ebaab03b..d19ae9861ed6 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -11,12 +11,16 @@ // //===----------------------------------------------------------------------===// -#include "clang/Frontend/InitHeaderSearch.h" -#include "clang/Lex/HeaderSearch.h" +#include "clang/Frontend/Utils.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" +#include "clang/Frontend/HeaderSearchOptions.h" +#include "clang/Lex/HeaderSearch.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/Config/config.h" @@ -26,6 +30,66 @@ #include <windows.h> #endif using namespace clang; +using namespace clang::frontend; + +namespace { + +/// InitHeaderSearch - This class makes it easier to set the search paths of +/// a HeaderSearch object. InitHeaderSearch stores several search path lists +/// internally, which can be sent to a HeaderSearch object in one swoop. +class InitHeaderSearch { + std::vector<DirectoryLookup> IncludeGroup[4]; + HeaderSearch& Headers; + bool Verbose; + std::string isysroot; + +public: + + InitHeaderSearch(HeaderSearch &HS, + bool verbose = false, const std::string &iSysroot = "") + : Headers(HS), Verbose(verbose), isysroot(iSysroot) {} + + /// AddPath - Add the specified path to the specified group list. + void AddPath(const llvm::StringRef &Path, IncludeDirGroup Group, + bool isCXXAware, bool isUserSupplied, + bool isFramework, bool IgnoreSysRoot = false); + + /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to suport a gnu + /// libstdc++. + void AddGnuCPlusPlusIncludePaths(const std::string &Base, + const char *ArchDir, + const char *Dir32, + const char *Dir64, + const llvm::Triple &triple); + + /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW + /// libstdc++. + void AddMinGWCPlusPlusIncludePaths(const std::string &Base, + const char *Arch, + const char *Version); + + /// AddDelimitedPaths - Add a list of paths delimited by the system PATH + /// separator. The processing follows that of the CPATH variable for gcc. + void AddDelimitedPaths(const char *String); + + // AddDefaultCIncludePaths - Add paths that should always be searched. + void AddDefaultCIncludePaths(const llvm::Triple &triple); + + // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when + // compiling c++. + void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple); + + /// AddDefaultSystemIncludePaths - Adds the default system include paths so + /// that e.g. stdio.h is found. + void AddDefaultSystemIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple); + + /// Realize - Merges all search path lists into one list and send it to + /// HeaderSearch. + void Realize(); +}; + +} void InitHeaderSearch::AddPath(const llvm::StringRef &Path, IncludeDirGroup Group, bool isCXXAware, @@ -82,9 +146,8 @@ void InitHeaderSearch::AddPath(const llvm::StringRef &Path, } -void InitHeaderSearch::AddEnvVarPaths(const char *Name) { - const char* at = getenv(Name); - if (!at || *at == 0) // Empty string should not add '.' path. +void InitHeaderSearch::AddDelimitedPaths(const char *at) { + if (*at == 0) // Empty string should not add '.' path. return; const char* delim = strchr(at, llvm::sys::PathSeparator); @@ -103,27 +166,30 @@ void InitHeaderSearch::AddEnvVarPaths(const char *Name) { } void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base, + const char *ArchDir, const char *Dir32, const char *Dir64, const llvm::Triple &triple) { + // Add the common dirs + AddPath(Base, System, true, false, false); + AddPath(Base + "/backward", System, true, false, false); + + // Add the multilib dirs llvm::Triple::ArchType arch = triple.getArch(); bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64; - - AddPath(Base, System, true, false, false); if (is64bit) - AddPath(Base + "/" + Dir64, System, true, false, false); + AddPath(Base + "/" + ArchDir + "/" + Dir64, System, true, false, false); else - AddPath(Base + "/" + Dir32, System, true, false, false); - AddPath(Base + "/backward", System, true, false, false); + AddPath(Base + "/" + ArchDir + "/" + Dir32, System, true, false, false); } void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base, const char *Arch, const char *Version) { - std::string localBase = Base + "/" + Arch + "/" + Version + "/include"; - AddPath(localBase, System, true, false, false); - AddPath(localBase + "/c++", System, true, false, false); - AddPath(localBase + "/c++/backward", System, true, false, false); + std::string localBase = Base + "/" + Arch + "/" + Version + "/include"; + AddPath(localBase, System, true, false, false); + AddPath(localBase + "/c++", System, true, false, false); + AddPath(localBase + "/c++/backward", System, true, false, false); } // FIXME: This probably should goto to some platform utils place. @@ -243,6 +309,16 @@ bool getVisualStudioDir(std::string &path) { void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { // FIXME: temporary hack: hard-coded paths. + llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + llvm::SmallVector<llvm::StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (llvm::SmallVectorImpl<llvm::StringRef>::iterator i = dirs.begin(); + i != dirs.end(); + ++i) + AddPath(*i, System, false, false, false); + return; + } llvm::Triple::OSType os = triple.getOS(); switch (os) { case llvm::Triple::Win32: @@ -288,6 +364,17 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { llvm::Triple::OSType os = triple.getOS(); + llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT); + if (CxxIncludeRoot != "") { + llvm::StringRef CxxIncludeArch(CXX_INCLUDE_ARCH); + if (CxxIncludeArch == "") + AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(), + CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple); + else + AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, CXX_INCLUDE_ARCH, + CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple); + return; + } // FIXME: temporary hack: hard-coded paths. switch (os) { case llvm::Triple::Cygwin: @@ -310,113 +397,77 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl break; case llvm::Triple::Darwin: AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "i686-apple-darwin10", - "i686-apple-darwin10/x86_64", - triple); + "i686-apple-darwin10", "", "x86_64", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", - "i686-apple-darwin8", - "i686-apple-darwin8", - triple); + "i686-apple-darwin8", "", "", triple); break; case llvm::Triple::Linux: // Ubuntu 7.10 - Gutsy Gibbon AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3", - "i486-linux-gnu", - "i486-linux-gnu", - triple); + "i486-linux-gnu", "", "", triple); // Ubuntu 9.04 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3", - "x86_64-linux-gnu/32", - "x86_64-linux-gnu", - triple); + "x86_64-linux-gnu","32", "", triple); + // Ubuntu 9.10 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", + "x86_64-linux-gnu", "32", "", triple); // Fedora 8 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", - "i386-redhat-linux", - "i386-redhat-linux", - triple); + "i386-redhat-linux", "", "", triple); // Fedora 9 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", - "i386-redhat-linux", - "i386-redhat-linux", - triple); + "i386-redhat-linux", "", "", triple); // Fedora 10 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", - "i386-redhat-linux", - "i386-redhat-linux", - triple); + "i386-redhat-linux","", "", triple); + + // Fedora 11 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", + "i586-redhat-linux","", "", triple); + // openSUSE 11.1 32 bit AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i586-suse-linux", - "i586-suse-linux", - triple); + "i586-suse-linux", "", "", triple); // openSUSE 11.1 64 bit AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "x86_64-suse-linux/32", - "x86_64-suse-linux", - triple); + "x86_64-suse-linux", "32", "", triple); // openSUSE 11.2 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "i586-suse-linux", - "i586-suse-linux", - triple); + "i586-suse-linux", "", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "x86_64-suse-linux", - "x86_64-suse-linux", - triple); + "x86_64-suse-linux", "", "", triple); // Arch Linux 2008-06-24 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + "i686-pc-linux-gnu", "", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", - "x86_64-unknown-linux-gnu", - "x86_64-unknown-linux-gnu", - triple); + "x86_64-unknown-linux-gnu", "", "", triple); // Gentoo x86 2009.1 stable AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); // Gentoo x86 2009.0 stable AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); // Gentoo x86 2008.0 stable AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); // Ubuntu 8.10 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-pc-linux-gnu", - "i486-pc-linux-gnu", - triple); + "i486-pc-linux-gnu", "", "", triple); // Ubuntu 9.04 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-linux-gnu", - "i486-linux-gnu", - triple); + "i486-linux-gnu","", "", triple); // Gentoo amd64 stable AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + "i686-pc-linux-gnu", "", "", triple); // Exherbo (2009-10-26) - AddGnuCPlusPlusIncludePaths( - "/usr/include/c++/4.4.2", - "x86_64-pc-linux-gnu/32", - "x86_64-pc-linux-gnu", - triple); - AddGnuCPlusPlusIncludePaths( - "/usr/include/c++/4.4.2", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "x86_64-pc-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "i686-pc-linux-gnu", "", "", triple); break; case llvm::Triple::FreeBSD: // DragonFly @@ -429,44 +480,27 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl case llvm::Triple::AuroraUX: // AuroraUX AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4", - "i386-pc-solaris2.11", - "i386-pc-solaris2.11", - triple); + "i386-pc-solaris2.11", "", "", triple); break; default: break; } } -void InitHeaderSearch::AddDefaultFrameworkIncludePaths(const llvm::Triple &triple) { - llvm::Triple::OSType os = triple.getOS(); - if (os != llvm::Triple::Darwin) - return; - AddPath("/System/Library/Frameworks", System, true, false, true); - AddPath("/Library/Frameworks", System, true, false, true); -} - void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, const llvm::Triple &triple) { AddDefaultCIncludePaths(triple); - AddDefaultFrameworkIncludePaths(triple); + + // Add the default framework include paths on Darwin. + if (triple.getOS() == llvm::Triple::Darwin) { + AddPath("/System/Library/Frameworks", System, true, false, true); + AddPath("/Library/Frameworks", System, true, false, true); + } + if (Lang.CPlusPlus) AddDefaultCPlusPlusIncludePaths(triple); } -void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) { - AddEnvVarPaths("CPATH"); - if (Lang.CPlusPlus && Lang.ObjC1) - AddEnvVarPaths("OBJCPLUS_INCLUDE_PATH"); - else if (Lang.CPlusPlus) - AddEnvVarPaths("CPLUS_INCLUDE_PATH"); - else if (Lang.ObjC1) - AddEnvVarPaths("OBJC_INCLUDE_PATH"); - else - AddEnvVarPaths("C_INCLUDE_PATH"); -} - - /// RemoveDuplicates - If there are duplicate directory entries in the specified /// search list, remove the later (dead) ones. static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, @@ -591,3 +625,40 @@ void InitHeaderSearch::Realize() { fprintf(stderr, "End of search list.\n"); } } + +void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, + const HeaderSearchOptions &HSOpts, + const LangOptions &Lang, + const llvm::Triple &Triple) { + InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot); + + // Add the user defined entries. + for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) { + const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i]; + Init.AddPath(E.Path, E.Group, false, E.IsUserSupplied, E.IsFramework, + false); + } + + // Add entries from CPATH and friends. + Init.AddDelimitedPaths(HSOpts.EnvIncPath.c_str()); + if (Lang.CPlusPlus && Lang.ObjC1) + Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath.c_str()); + else if (Lang.CPlusPlus) + Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath.c_str()); + else if (Lang.ObjC1) + Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath.c_str()); + else + Init.AddDelimitedPaths(HSOpts.CEnvIncPath.c_str()); + + if (!HSOpts.BuiltinIncludePath.empty()) { + // Ignore the sys root, we *always* look for clang headers relative to + // supplied path. + Init.AddPath(HSOpts.BuiltinIncludePath, System, + false, false, false, /*IgnoreSysRoot=*/ true); + } + + if (HSOpts.UseStandardIncludes) + Init.AddDefaultSystemIncludePaths(Lang, Triple); + + Init.Realize(); +} diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 7139e55f0b60..4ee286dd265d 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -11,8 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Frontend/InitPreprocessor.h" +#include "clang/Frontend/Utils.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/PreprocessorOptions.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/STLExtras.h" @@ -60,9 +61,7 @@ static void UndefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) { Buf.push_back('\n'); } -/// Add the quoted name of an implicit include file. -static void AddQuotedIncludePath(std::vector<char> &Buf, - const std::string &File) { +std::string clang::NormalizeDashIncludePath(llvm::StringRef File) { // Implicit include paths should be resolved relative to the current // working directory first, and then use the regular header search // mechanism. The proper way to handle this is to have the @@ -75,9 +74,16 @@ static void AddQuotedIncludePath(std::vector<char> &Buf, if (!Path.exists()) Path = File; + return Lexer::Stringify(Path.str()); +} + +/// Add the quoted name of an implicit include file. +static void AddQuotedIncludePath(std::vector<char> &Buf, + const std::string &File) { + // Escape double quotes etc. Buf.push_back('"'); - std::string EscapedFile = Lexer::Stringify(Path.str()); + std::string EscapedFile = NormalizeDashIncludePath(File); Buf.insert(Buf.end(), EscapedFile.begin(), EscapedFile.end()); Buf.push_back('"'); } @@ -216,6 +222,14 @@ static void DefineTypeSize(const char *MacroName, unsigned TypeWidth, DefineBuiltinMacro(Buf, MacroBuf); } +/// DefineTypeSize - An overloaded helper that uses TargetInfo to determine +/// the width, suffix, and signedness of the given type +static void DefineTypeSize(const char *MacroName, TargetInfo::IntType Ty, + const TargetInfo &TI, std::vector<char> &Buf) { + DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty), + TI.isTypeSigned(Ty), Buf); +} + static void DefineType(const char *MacroName, TargetInfo::IntType Ty, std::vector<char> &Buf) { char MacroBuf[60]; @@ -223,6 +237,20 @@ static void DefineType(const char *MacroName, TargetInfo::IntType Ty, DefineBuiltinMacro(Buf, MacroBuf); } +static void DefineExactWidthIntType(TargetInfo::IntType Ty, + const TargetInfo &TI, std::vector<char> &Buf) { + char MacroBuf[60]; + int TypeWidth = TI.getTypeWidth(Ty); + sprintf(MacroBuf, "__INT%d_TYPE__", TypeWidth); + DefineType(MacroBuf, Ty, Buf); + + + const char *ConstSuffix = TargetInfo::getTypeConstantSuffix(Ty); + if (strlen(ConstSuffix) > 0) { + sprintf(MacroBuf, "__INT%d_C_SUFFIX__=%s", TypeWidth, ConstSuffix); + DefineBuiltinMacro(Buf, MacroBuf); + } +} static void InitializePredefinedMacros(const TargetInfo &TI, const LangOptions &LangOpts, @@ -346,14 +374,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineBuiltinMacro(Buf, "__CHAR_BIT__=8"); DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Buf); - DefineTypeSize("__SHRT_MAX__", TI.getShortWidth(), "", true, Buf); - DefineTypeSize("__INT_MAX__", TI.getIntWidth(), "", true, Buf); - DefineTypeSize("__LONG_MAX__", TI.getLongWidth(), "L", true, Buf); - DefineTypeSize("__LONG_LONG_MAX__", TI.getLongLongWidth(), "LL", true, Buf); - DefineTypeSize("__WCHAR_MAX__", TI.getWCharWidth(), "", true, Buf); - TargetInfo::IntType IntMaxType = TI.getIntMaxType(); - DefineTypeSize("__INTMAX_MAX__", TI.getTypeWidth(IntMaxType), - TI.getTypeConstantSuffix(IntMaxType), true, Buf); + DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Buf); + DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Buf); + DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Buf); + DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Buf); + DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Buf); + DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Buf); DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf); DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf); @@ -374,23 +400,22 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (!LangOpts.CharIsSigned) DefineBuiltinMacro(Buf, "__CHAR_UNSIGNED__"); - // Define fixed-sized integer types for stdint.h - assert(TI.getCharWidth() == 8 && "unsupported target types"); - assert(TI.getShortWidth() == 16 && "unsupported target types"); - DefineBuiltinMacro(Buf, "__INT8_TYPE__=char"); - DefineBuiltinMacro(Buf, "__INT16_TYPE__=short"); - - if (TI.getIntWidth() == 32) - DefineBuiltinMacro(Buf, "__INT32_TYPE__=int"); - else { - assert(TI.getLongLongWidth() == 32 && "unsupported target types"); - DefineBuiltinMacro(Buf, "__INT32_TYPE__=long long"); - } - - // 16-bit targets doesn't necessarily have a 64-bit type. - if (TI.getLongLongWidth() == 64) - DefineType("__INT64_TYPE__", TI.getInt64Type(), Buf); + // Define exact-width integer types for stdint.h + sprintf(MacroBuf, "__INT%d_TYPE__=char", TI.getCharWidth()); + DefineBuiltinMacro(Buf, MacroBuf); + if (TI.getShortWidth() > TI.getCharWidth()) + DefineExactWidthIntType(TargetInfo::SignedShort, TI, Buf); + + if (TI.getIntWidth() > TI.getShortWidth()) + DefineExactWidthIntType(TargetInfo::SignedInt, TI, Buf); + + if (TI.getLongWidth() > TI.getIntWidth()) + DefineExactWidthIntType(TargetInfo::SignedLong, TI, Buf); + + if (TI.getLongLongWidth() > TI.getLongWidth()) + DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Buf); + // Add __builtin_va_list typedef. { const char *VAList = TI.getVAListDeclaration(); @@ -443,7 +468,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, /// environment ready to process a single file. This returns true on error. /// void clang::InitializePreprocessor(Preprocessor &PP, - const PreprocessorInitOptions &InitOpts) { + const PreprocessorOptions &InitOpts, + const HeaderSearchOptions &HSOpts) { std::vector<char> PredefineBuffer; const char *LineDirective = "# 1 \"<built-in>\" 3\n"; @@ -451,7 +477,7 @@ void clang::InitializePreprocessor(Preprocessor &PP, LineDirective, LineDirective+strlen(LineDirective)); // Install things like __POWERPC__, __GNUC__, etc into the macro table. - if (InitOpts.getUsePredefines()) + if (InitOpts.UsePredefines) InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), PredefineBuffer); @@ -462,30 +488,33 @@ void clang::InitializePreprocessor(Preprocessor &PP, LineDirective, LineDirective+strlen(LineDirective)); // Process #define's and #undef's in the order they are given. - for (PreprocessorInitOptions::macro_iterator I = InitOpts.macro_begin(), - E = InitOpts.macro_end(); I != E; ++I) { - if (I->second) // isUndef - UndefineBuiltinMacro(PredefineBuffer, I->first.c_str()); + for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) { + if (InitOpts.Macros[i].second) // isUndef + UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); else - DefineBuiltinMacro(PredefineBuffer, I->first.c_str()); + DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); } // If -imacros are specified, include them now. These are processed before // any -include directives. - for (PreprocessorInitOptions::imacro_iterator I = InitOpts.imacro_begin(), - E = InitOpts.imacro_end(); I != E; ++I) - AddImplicitIncludeMacros(PredefineBuffer, *I); + for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i) + AddImplicitIncludeMacros(PredefineBuffer, InitOpts.MacroIncludes[i]); // Process -include directives. - for (PreprocessorInitOptions::include_iterator I = InitOpts.include_begin(), - E = InitOpts.include_end(); I != E; ++I) { - if (I->second) // isPTH - AddImplicitIncludePTH(PredefineBuffer, PP, I->first); + for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) { + const std::string &Path = InitOpts.Includes[i]; + if (Path == InitOpts.ImplicitPTHInclude) + AddImplicitIncludePTH(PredefineBuffer, PP, Path); else - AddImplicitInclude(PredefineBuffer, I->first); + AddImplicitInclude(PredefineBuffer, Path); } // Null terminate PredefinedBuffer and add it. PredefineBuffer.push_back(0); PP.setPredefines(&PredefineBuffer[0]); + + // Initialize the header search object. + ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts, + PP.getLangOptions(), + PP.getTargetInfo().getTriple()); } diff --git a/lib/Frontend/ManagerRegistry.cpp b/lib/Frontend/ManagerRegistry.cpp deleted file mode 100644 index 79f1e8178e10..000000000000 --- a/lib/Frontend/ManagerRegistry.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===- ManagerRegistry.cpp - Pluggble Analyzer module creators --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the pluggable analyzer module creators. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/ManagerRegistry.h" - -using namespace clang; - -StoreManagerCreator ManagerRegistry::StoreMgrCreator = 0; - -ConstraintManagerCreator ManagerRegistry::ConstraintMgrCreator = 0; diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 26f426ba329b..ca7aa3260c62 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -13,6 +13,7 @@ #include "clang/Frontend/PCHReader.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/Utils.h" #include "../Sema/Sema.h" // FIXME: move Sema headers elsewhere #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -104,6 +105,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline); PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control); PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed); + PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar); if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) { Reader.Diag(diag::warn_pch_gc_mode) << LangOpts.getGCMode() << PPLangOpts.getGCMode(); @@ -121,83 +123,56 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { return false; } -bool PCHValidator::ReadTargetTriple(const std::string &Triple) { - if (Triple != PP.getTargetInfo().getTriple().getTriple()) { - Reader.Diag(diag::warn_pch_target_triple) - << Triple << PP.getTargetInfo().getTriple().getTriple(); - return true; - } - return false; -} - -/// \brief Split the given string into a vector of lines, eliminating -/// any empty lines in the process. -/// -/// \param Str the string to split. -/// \param Len the length of Str. -/// \param KeepEmptyLines true if empty lines should be included -/// \returns a vector of lines, with the line endings removed -static std::vector<std::string> splitLines(const char *Str, unsigned Len, - bool KeepEmptyLines = false) { - std::vector<std::string> Lines; - for (unsigned LineStart = 0; LineStart < Len; ++LineStart) { - unsigned LineEnd = LineStart; - while (LineEnd < Len && Str[LineEnd] != '\n') - ++LineEnd; - if (LineStart != LineEnd || KeepEmptyLines) - Lines.push_back(std::string(&Str[LineStart], &Str[LineEnd])); - LineStart = LineEnd; - } - return Lines; -} - -/// \brief Determine whether the string Haystack starts with the -/// substring Needle. -static bool startsWith(const std::string &Haystack, const char *Needle) { - for (unsigned I = 0, N = Haystack.size(); Needle[I] != 0; ++I) { - if (I == N) - return false; - if (Haystack[I] != Needle[I]) - return false; - } +bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) { + if (Triple == PP.getTargetInfo().getTriple().str()) + return false; + Reader.Diag(diag::warn_pch_target_triple) + << Triple << PP.getTargetInfo().getTriple().str(); return true; } -/// \brief Determine whether the string Haystack starts with the -/// substring Needle. -static inline bool startsWith(const std::string &Haystack, - const std::string &Needle) { - return startsWith(Haystack, Needle.c_str()); -} - -bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, - unsigned PCHPredefLen, +bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, FileID PCHBufferID, + llvm::StringRef OriginalFileName, std::string &SuggestedPredefines) { - const char *Predef = PP.getPredefines().c_str(); - unsigned PredefLen = PP.getPredefines().size(); - - // If the two predefines buffers compare equal, we're done! - if (PredefLen == PCHPredefLen && - strncmp(Predef, PCHPredef, PCHPredefLen) == 0) + // We are in the context of an implicit include, so the predefines buffer will + // have a #include entry for the PCH file itself (as normalized by the + // preprocessor initialization). Find it and skip over it in the checking + // below. + llvm::SmallString<256> PCHInclude; + PCHInclude += "#include \""; + PCHInclude += NormalizeDashIncludePath(OriginalFileName); + PCHInclude += "\"\n"; + std::pair<llvm::StringRef,llvm::StringRef> Split = + llvm::StringRef(PP.getPredefines()).split(PCHInclude.str()); + llvm::StringRef Left = Split.first, Right = Split.second; + assert(Left != PP.getPredefines() && "Missing PCH include entry!"); + + // If the predefines is equal to the joined left and right halves, we're done! + if (Left.size() + Right.size() == PCHPredef.size() && + PCHPredef.startswith(Left) && PCHPredef.endswith(Right)) return false; SourceManager &SourceMgr = PP.getSourceManager(); - // The predefines buffers are different. Determine what the - // differences are, and whether they require us to reject the PCH - // file. - std::vector<std::string> CmdLineLines = splitLines(Predef, PredefLen); - std::vector<std::string> PCHLines = splitLines(PCHPredef, PCHPredefLen); + // The predefines buffers are different. Determine what the differences are, + // and whether they require us to reject the PCH file. + llvm::SmallVector<llvm::StringRef, 8> PCHLines; + PCHPredef.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + + llvm::SmallVector<llvm::StringRef, 8> CmdLineLines; + Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + Right.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - // Sort both sets of predefined buffer lines, since + // Sort both sets of predefined buffer lines, since we allow some extra + // definitions and they may appear at any point in the output. std::sort(CmdLineLines.begin(), CmdLineLines.end()); std::sort(PCHLines.begin(), PCHLines.end()); - // Determine which predefines that where used to build the PCH file - // are missing from the command line. - std::vector<std::string> MissingPredefines; + // Determine which predefines that were used to build the PCH file are missing + // from the command line. + std::vector<llvm::StringRef> MissingPredefines; std::set_difference(PCHLines.begin(), PCHLines.end(), CmdLineLines.begin(), CmdLineLines.end(), std::back_inserter(MissingPredefines)); @@ -205,31 +180,30 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, bool MissingDefines = false; bool ConflictingDefines = false; for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) { - const std::string &Missing = MissingPredefines[I]; - if (!startsWith(Missing, "#define ") != 0) { + llvm::StringRef Missing = MissingPredefines[I]; + if (!Missing.startswith("#define ")) { Reader.Diag(diag::warn_pch_compiler_options_mismatch); return true; } - // This is a macro definition. Determine the name of the macro - // we're defining. + // This is a macro definition. Determine the name of the macro we're + // defining. std::string::size_type StartOfMacroName = strlen("#define "); std::string::size_type EndOfMacroName = Missing.find_first_of("( \n\r", StartOfMacroName); assert(EndOfMacroName != std::string::npos && "Couldn't find the end of the macro name"); - std::string MacroName = Missing.substr(StartOfMacroName, - EndOfMacroName - StartOfMacroName); + llvm::StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName); - // Determine whether this macro was given a different definition - // on the command line. - std::string MacroDefStart = "#define " + MacroName; + // Determine whether this macro was given a different definition on the + // command line. + std::string MacroDefStart = "#define " + MacroName.str(); std::string::size_type MacroDefLen = MacroDefStart.size(); - std::vector<std::string>::iterator ConflictPos + llvm::SmallVector<llvm::StringRef, 8>::iterator ConflictPos = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(), MacroDefStart); for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) { - if (!startsWith(*ConflictPos, MacroDefStart)) { + if (!ConflictPos->startswith(MacroDefStart)) { // Different macro; we're done. ConflictPos = CmdLineLines.end(); break; @@ -250,21 +224,18 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, << MacroName; // Show the definition of this macro within the PCH file. - const char *MissingDef = strstr(PCHPredef, Missing.c_str()); - unsigned Offset = MissingDef - PCHPredef; - SourceLocation PCHMissingLoc - = SourceMgr.getLocForStartOfFile(PCHBufferID) - .getFileLocWithOffset(Offset); - Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) - << MacroName; + llvm::StringRef::size_type Offset = PCHPredef.find(Missing); + assert(Offset != llvm::StringRef::npos && "Unable to find macro!"); + SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID) + .getFileLocWithOffset(Offset); + Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName; ConflictingDefines = true; continue; } - // If the macro doesn't conflict, then we'll just pick up the - // macro definition from the PCH file. Warn the user that they - // made a mistake. + // If the macro doesn't conflict, then we'll just pick up the macro + // definition from the PCH file. Warn the user that they made a mistake. if (ConflictingDefines) continue; // Don't complain if there are already conflicting defs @@ -274,10 +245,9 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, } // Show the definition of this macro within the PCH file. - const char *MissingDef = strstr(PCHPredef, Missing.c_str()); - unsigned Offset = MissingDef - PCHPredef; - SourceLocation PCHMissingLoc - = SourceMgr.getLocForStartOfFile(PCHBufferID) + llvm::StringRef::size_type Offset = PCHPredef.find(Missing); + assert(Offset != llvm::StringRef::npos && "Unable to find macro!"); + SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID) .getFileLocWithOffset(Offset); Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch); } @@ -289,13 +259,13 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, // parameters that were not present when building the PCH // file. Extra #defines are okay, so long as the identifiers being // defined were not used within the precompiled header. - std::vector<std::string> ExtraPredefines; + std::vector<llvm::StringRef> ExtraPredefines; std::set_difference(CmdLineLines.begin(), CmdLineLines.end(), PCHLines.begin(), PCHLines.end(), std::back_inserter(ExtraPredefines)); for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) { - const std::string &Extra = ExtraPredefines[I]; - if (!startsWith(Extra, "#define ") != 0) { + llvm::StringRef &Extra = ExtraPredefines[I]; + if (!Extra.startswith("#define ")) { Reader.Diag(diag::warn_pch_compiler_options_mismatch); return true; } @@ -307,16 +277,13 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, = Extra.find_first_of("( \n\r", StartOfMacroName); assert(EndOfMacroName != std::string::npos && "Couldn't find the end of the macro name"); - std::string MacroName = Extra.substr(StartOfMacroName, - EndOfMacroName - StartOfMacroName); + llvm::StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName); // Check whether this name was used somewhere in the PCH file. If // so, defining it as a macro could change behavior, so we reject // the PCH file. - if (IdentifierInfo *II = Reader.get(MacroName.c_str(), - MacroName.c_str() + MacroName.size())) { - Reader.Diag(diag::warn_macro_name_used_in_pch) - << II; + if (IdentifierInfo *II = Reader.get(MacroName)) { + Reader.Diag(diag::warn_macro_name_used_in_pch) << II; return true; } @@ -650,11 +617,11 @@ bool PCHReader::Error(const char *Msg) { /// /// \returns true if there was a mismatch (in which case the PCH file /// should be ignored), or false otherwise. -bool PCHReader::CheckPredefinesBuffer(const char *PCHPredef, - unsigned PCHPredefLen, +bool PCHReader::CheckPredefinesBuffer(llvm::StringRef PCHPredef, FileID PCHBufferID) { if (Listener) - return Listener->ReadPredefinesBuffer(PCHPredef, PCHPredefLen, PCHBufferID, + return Listener->ReadPredefinesBuffer(PCHPredef, PCHBufferID, + ActualOriginalFileName, SuggestedPredefines); return false; } @@ -1364,7 +1331,8 @@ PCHReader::ReadPCHBlock() { break; case pch::ORIGINAL_FILE_NAME: - OriginalFileName.assign(BlobStart, BlobLen); + ActualOriginalFileName.assign(BlobStart, BlobLen); + OriginalFileName = ActualOriginalFileName; MaybeAddSystemRootToFilename(OriginalFileName); break; @@ -1403,10 +1371,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { // // FIXME: This shouldn't be here, we should just take a raw_ostream. std::string ErrStr; - if (FileName == "-") - Buffer.reset(llvm::MemoryBuffer::getSTDIN()); - else - Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &ErrStr)); + Buffer.reset(llvm::MemoryBuffer::getFileOrSTDIN(FileName, &ErrStr)); if (!Buffer) { Error(ErrStr.c_str()); return IgnorePCH; @@ -1478,7 +1443,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { } // Check the predefines buffer. - if (CheckPredefinesBuffer(PCHPredefines, PCHPredefinesLen, + if (CheckPredefinesBuffer(llvm::StringRef(PCHPredefines, PCHPredefinesLen), PCHPredefinesBufferID)) return IgnorePCH; @@ -1741,6 +1706,7 @@ bool PCHReader::ParseLanguageOptions( PARSE_LANGOPT(NoInline); PARSE_LANGOPT(AccessControl); PARSE_LANGOPT(CharIsSigned); + PARSE_LANGOPT(ShortWChar); LangOpts.setGCMode((LangOptions::GCMode)Record[Idx]); ++Idx; LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx]); @@ -2213,6 +2179,14 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, return ReadDeclExpr(); case TemplateArgument::Type: return GetDeclaratorInfo(Record, Index); + case TemplateArgument::Template: { + SourceLocation + QualStart = SourceLocation::getFromRawEncoding(Record[Index++]), + QualEnd = SourceLocation::getFromRawEncoding(Record[Index++]), + TemplateNameLoc = SourceLocation::getFromRawEncoding(Record[Index++]); + return TemplateArgumentLocInfo(SourceRange(QualStart, QualEnd), + TemplateNameLoc); + } case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index b9ece21f74c3..6a92a2db51a8 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -264,7 +264,12 @@ void PCHDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) { ClassRefs.reserve(NumClassRefs); for (unsigned I = 0; I != NumClassRefs; ++I) ClassRefs.push_back(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); - CD->setClassList(*Reader.getContext(), ClassRefs.data(), NumClassRefs); + llvm::SmallVector<SourceLocation, 16> SLocs; + SLocs.reserve(NumClassRefs); + for (unsigned I = 0; I != NumClassRefs; ++I) + SLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setClassList(*Reader.getContext(), ClassRefs.data(), SLocs.data(), + NumClassRefs); } void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) { @@ -442,6 +447,8 @@ Attr *PCHReader::ReadAttributes() { (BlocksAttr::BlocksAttrTypes)Record[Idx++]); break; + SIMPLE_ATTR(CDecl); + case Attr::Cleanup: New = ::new (*Context) CleanupAttr( cast<FunctionDecl>(GetDecl(Record[Idx++]))); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index de56166125ed..8a45ebce1b9d 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -765,6 +765,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { // be enabled. Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or // unsigned type + Record.push_back(LangOpts.ShortWChar); // force wchar_t to be unsigned short Record.push_back(LangOpts.getGCMode()); Record.push_back(LangOpts.getVisibilityMode()); Record.push_back(LangOpts.getStackProtectorMode()); @@ -1247,9 +1248,9 @@ void PCHWriter::WriteType(QualType T) { // Emit the type's representation. PCHTypeWriter W(*this, Record); - if (T.hasNonFastQualifiers()) { - Qualifiers Qs = T.getQualifiers(); - AddTypeRef(T.getUnqualifiedType(), Record); + if (T.hasLocalNonFastQualifiers()) { + Qualifiers Qs = T.getLocalQualifiers(); + AddTypeRef(T.getLocalUnqualifiedType(), Record); Record.push_back(Qs.getAsOpaqueValue()); W.Code = pch::TYPE_EXT_QUAL; } else { @@ -1767,6 +1768,9 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { Record.push_back(cast<BlocksAttr>(Attr)->getType()); // FIXME: stable break; + case Attr::CDecl: + break; + case Attr::Cleanup: AddDeclRef(cast<CleanupAttr>(Attr)->getFunctionDecl(), Record); break; @@ -2118,6 +2122,12 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, case TemplateArgument::Type: AddDeclaratorInfo(Arg.getLocInfo().getAsDeclaratorInfo(), Record); break; + case TemplateArgument::Template: + Record.push_back( + Arg.getTemplateQualifierRange().getBegin().getRawEncoding()); + Record.push_back(Arg.getTemplateQualifierRange().getEnd().getRawEncoding()); + Record.push_back(Arg.getTemplateNameLoc().getRawEncoding()); + break; case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: @@ -2144,10 +2154,10 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { return; } - unsigned FastQuals = T.getFastQualifiers(); + unsigned FastQuals = T.getLocalFastQualifiers(); T.removeFastQualifiers(); - if (T.hasNonFastQualifiers()) { + if (T.hasLocalNonFastQualifiers()) { pch::TypeID &ID = TypeIDs[T]; if (ID == 0) { // We haven't seen these qualifiers applied to this type before. @@ -2162,7 +2172,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { return; } - assert(!T.hasQualifiers()); + assert(!T.hasLocalQualifiers()); if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) { pch::TypeID ID = 0; diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 8997e661a5a1..c7bfee2c8bcd 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -260,7 +260,9 @@ void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) { VisitDecl(D); Record.push_back(D->size()); for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) - Writer.AddDeclRef(*I, Record); + Writer.AddDeclRef(I->getInterface(), Record); + for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) + Writer.AddSourceLocation(I->getLocation(), Record); Code = pch::DECL_OBJC_CLASS; } diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index 1be9ea8b8c41..6bcf39a92a24 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -37,6 +37,7 @@ namespace { const std::string OutputFile; const LangOptions &LangOpts; llvm::OwningPtr<PathDiagnosticClient> SubPD; + bool flushed; public: PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, PathDiagnosticClient *subPD); @@ -61,7 +62,7 @@ namespace { PlistDiagnostics::PlistDiagnostics(const std::string& output, const LangOptions &LO, PathDiagnosticClient *subPD) - : OutputFile(output), LangOpts(LO), SubPD(subPD) {} + : OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false) {} PathDiagnosticClient* clang::CreatePlistDiagnosticClient(const std::string& s, const Preprocessor &PP, @@ -310,6 +311,11 @@ void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) { + + if (flushed) + return; + + flushed = true; // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. @@ -423,4 +429,6 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> if (FilesMade) FilesMade->push_back(OutputFile); + + BatchedDiags.clear(); } diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index 25b40c78183c..deb5498b906e 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -79,10 +79,11 @@ namespace { /// Scope will always be top level file scope. Action::DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, + SourceLocation *IdentLocs, unsigned NumElts) { Out << __FUNCTION__ << "\n"; return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList, - NumElts); + IdentLocs, NumElts); } // Pure Printing diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 630a093a4bf6..37424057809c 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -13,13 +13,14 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/Utils.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/PreprocessorOutputOptions.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PPCallbacks.h" -#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Pragma.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Lex/TokenConcatenation.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" @@ -439,7 +440,7 @@ namespace { }; } -void clang::DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { +static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { // -dM mode just scans and ignores all tokens in the files, then dumps out // the macro table at the end. PP.EnterMainSourceFile(); @@ -467,18 +468,23 @@ void clang::DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { /// DoPrintPreprocessedInput - This implements -E mode. /// void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, - bool EnableCommentOutput, - bool EnableMacroCommentOutput, - bool DisableLineMarkers, - bool DumpDefines) { + const PreprocessorOutputOptions &Opts) { + // Show macros with no output is handled specially. + if (!Opts.ShowCPP) { + assert(Opts.ShowMacros && "Not yet implemented!"); + DoPrintMacros(PP, OS); + return; + } + // Inform the preprocessor whether we want it to retain comments or not, due // to -C or -CC. - PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput); + PP.SetCommentRetentionState(Opts.ShowComments, Opts.ShowMacroComments); OS->SetBufferSize(64*1024); PrintPPOutputPPCallbacks *Callbacks = - new PrintPPOutputPPCallbacks(PP, *OS, DisableLineMarkers, DumpDefines); + new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers, + Opts.ShowMacros); PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks)); PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC", Callbacks)); diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 24ad69e3e0d3..06955e5c30b6 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -744,7 +744,7 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) { typedefString += "\n"; for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end(); I != E; ++I) { - ObjCInterfaceDecl *ForwardDecl = *I; + ObjCInterfaceDecl *ForwardDecl = I->getInterface(); typedefString += "#ifndef _REWRITER_typedef_"; typedefString += ForwardDecl->getNameAsString(); typedefString += "\n"; diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 4f8c804844b0..6ab0e1605276 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -39,9 +39,16 @@ static const enum llvm::raw_ostream::Colors savedColor = const unsigned WordWrapIndentation = 6; TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os, - const DiagnosticOptions &diags) + const DiagnosticOptions &diags, + bool _OwnsOutputStream) : OS(os), LangOpts(0), DiagOpts(&diags), - LastCaretDiagnosticWasNote(false) { + LastCaretDiagnosticWasNote(0), + OwnsOutputStream(_OwnsOutputStream) { +} + +TextDiagnosticPrinter::~TextDiagnosticPrinter() { + if (OwnsOutputStream) + delete &OS; } void TextDiagnosticPrinter:: diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp new file mode 100644 index 000000000000..2891aec50444 --- /dev/null +++ b/lib/Frontend/VerifyDiagnosticsClient.cpp @@ -0,0 +1,344 @@ +//===--- VerifyDiagnosticsClient.cpp - Verifying Diagnostic Client --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which buffers the diagnostic messages. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags, + DiagnosticClient *_Primary) + : Diags(_Diags), PrimaryClient(_Primary), + Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), NumErrors(0) { +} + +VerifyDiagnosticsClient::~VerifyDiagnosticsClient() { + CheckDiagnostics(); +} + +// DiagnosticClient interface. + +void VerifyDiagnosticsClient::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); + + PrimaryClient->BeginSourceFile(LangOpts, PP); +} + +void VerifyDiagnosticsClient::EndSourceFile() { + CheckDiagnostics(); + + PrimaryClient->EndSourceFile(); + + CurrentPreprocessor = 0; +} + +void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info) { + // 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); +} + +// FIXME: It would be nice to just get this from the primary diagnostic client +// or something. +bool VerifyDiagnosticsClient::HadErrors() { + CheckDiagnostics(); + + return NumErrors != 0; +} + +//===----------------------------------------------------------------------===// +// Checking diagnostics implementation. +//===----------------------------------------------------------------------===// + +typedef TextDiagnosticBuffer::DiagList DiagList; +typedef TextDiagnosticBuffer::const_iterator const_diag_iterator; + +/// FindDiagnostics - Go through the comment and see if it indicates expected +/// diagnostics. If so, then put them in a diagnostic list. +/// +static void FindDiagnostics(const char *CommentStart, unsigned CommentLen, + DiagList &ExpectedDiags, + Preprocessor &PP, SourceLocation Pos, + const char *ExpectedStr) { + const char *CommentEnd = CommentStart+CommentLen; + unsigned ExpectedStrLen = strlen(ExpectedStr); + + // Find all expected-foo diagnostics in the string and add them to + // ExpectedDiags. + while (CommentStart != CommentEnd) { + CommentStart = std::find(CommentStart, CommentEnd, 'e'); + if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return; + + // If this isn't expected-foo, ignore it. + if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) { + ++CommentStart; + continue; + } + + CommentStart += ExpectedStrLen; + + // Skip whitespace. + while (CommentStart != CommentEnd && + isspace(CommentStart[0])) + ++CommentStart; + + // Default, if we find the '{' now, is 1 time. + int Times = 1; + int Temp = 0; + // In extended syntax, there could be a digit now. + while (CommentStart != CommentEnd && + CommentStart[0] >= '0' && CommentStart[0] <= '9') { + Temp *= 10; + Temp += CommentStart[0] - '0'; + ++CommentStart; + } + if (Temp > 0) + Times = Temp; + + // Skip whitespace again. + while (CommentStart != CommentEnd && + isspace(CommentStart[0])) + ++CommentStart; + + // We should have a {{ now. + if (CommentEnd-CommentStart < 2 || + CommentStart[0] != '{' || CommentStart[1] != '{') { + if (std::find(CommentStart, CommentEnd, '{') != CommentEnd) + PP.Diag(Pos, diag::err_verify_bogus_characters); + else + PP.Diag(Pos, diag::err_verify_missing_start); + return; + } + CommentStart += 2; + + // Find the }}. + const char *ExpectedEnd = CommentStart; + while (1) { + ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}'); + if (CommentEnd-ExpectedEnd < 2) { + PP.Diag(Pos, diag::err_verify_missing_end); + return; + } + + if (ExpectedEnd[1] == '}') + break; + + ++ExpectedEnd; // Skip over singular }'s + } + + std::string Msg(CommentStart, ExpectedEnd); + std::string::size_type FindPos; + while ((FindPos = Msg.find("\\n")) != std::string::npos) + Msg.replace(FindPos, 2, "\n"); + // Add is possibly multiple times. + for (int i = 0; i < Times; ++i) + ExpectedDiags.push_back(std::make_pair(Pos, Msg)); + + CommentStart = ExpectedEnd; + } +} + +/// FindExpectedDiags - Lex the main source file to find all of the +// expected errors and warnings. +static void FindExpectedDiags(Preprocessor &PP, + DiagList &ExpectedErrors, + DiagList &ExpectedWarnings, + DiagList &ExpectedNotes) { + // Create a raw lexer to pull all the comments out of the main file. We don't + // want to look in #include'd headers for expected-error strings. + FileID FID = PP.getSourceManager().getMainFileID(); + if (PP.getSourceManager().getMainFileID().isInvalid()) + return; + + // Create a lexer to lex all the tokens of the main file in raw mode. + Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions()); + + // Return comments as tokens, this is how we find expected diagnostics. + RawLex.SetCommentRetentionState(true); + + Token Tok; + Tok.setKind(tok::comment); + while (Tok.isNot(tok::eof)) { + RawLex.Lex(Tok); + if (!Tok.is(tok::comment)) continue; + + std::string Comment = PP.getSpelling(Tok); + if (Comment.empty()) continue; + + // Find all expected errors. + FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP, + Tok.getLocation(), "expected-error"); + + // Find all expected warnings. + FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP, + Tok.getLocation(), "expected-warning"); + + // Find all expected notes. + FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP, + Tok.getLocation(), "expected-note"); + }; +} + +/// 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(Diagnostic &Diags, SourceManager *SourceMgr, + const_diag_iterator diag_begin, + const_diag_iterator diag_end, + const char *Kind, bool Expected) { + if (diag_begin == diag_end) return 0; + + llvm::SmallString<256> Fmt; + llvm::raw_svector_ostream OS(Fmt); + for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) { + if (I->first.isInvalid() || !SourceMgr) + OS << "\n (frontend)"; + else + OS << "\n Line " << SourceMgr->getInstantiationLineNumber(I->first); + OS << ": " << I->second; + } + + Diags.Report(diag::err_verify_inconsistent_diags) + << Kind << !Expected << OS.str(); + return std::distance(diag_begin, diag_end); +} + +/// CompareDiagLists - Compare two diagnostic lists and return the difference +/// between them. +/// +static unsigned CompareDiagLists(Diagnostic &Diags, + SourceManager &SourceMgr, + const_diag_iterator d1_begin, + const_diag_iterator d1_end, + const_diag_iterator d2_begin, + const_diag_iterator d2_end, + const char *Label) { + DiagList LeftOnly; + DiagList Left(d1_begin, d1_end); + DiagList Right(d2_begin, d2_end); + + for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) { + unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first); + const std::string &Diag1 = I->second; + + DiagList::iterator II, IE; + for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { + unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first); + if (LineNo1 != LineNo2) continue; + + const std::string &Diag2 = II->second; + if (Diag2.find(Diag1) != std::string::npos || + Diag1.find(Diag2) != std::string::npos) { + break; + } + } + if (II == IE) { + // Not found. + LeftOnly.push_back(*I); + } else { + // Found. The same cannot be found twice. + Right.erase(II); + } + } + // Now all that's left in Right are those that were not matched. + + return (PrintProblem(Diags, &SourceMgr, + LeftOnly.begin(), LeftOnly.end(), Label, true) + + PrintProblem(Diags, &SourceMgr, + Right.begin(), Right.end(), Label, false)); +} + +/// CheckResults - This compares the expected results to those that +/// were actually reported. It emits any discrepencies. Return "true" if there +/// were problems. Return "false" otherwise. +/// +static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr, + const TextDiagnosticBuffer &Buffer, + const DiagList &ExpectedErrors, + const DiagList &ExpectedWarnings, + const DiagList &ExpectedNotes) { + // We want to capture the delta between what was expected and what was + // seen. + // + // Expected \ Seen - set expected but not seen + // Seen \ Expected - set seen but not expected + unsigned NumProblems = 0; + + // See if there are error mismatches. + NumProblems += CompareDiagLists(Diags, SourceMgr, + ExpectedErrors.begin(), ExpectedErrors.end(), + Buffer.err_begin(), Buffer.err_end(), + "error"); + + // See if there are warning mismatches. + NumProblems += CompareDiagLists(Diags, SourceMgr, + ExpectedWarnings.begin(), + ExpectedWarnings.end(), + Buffer.warn_begin(), Buffer.warn_end(), + "warning"); + + // See if there are note mismatches. + NumProblems += CompareDiagLists(Diags, SourceMgr, + ExpectedNotes.begin(), + ExpectedNotes.end(), + Buffer.note_begin(), Buffer.note_end(), + "note"); + + return NumProblems; +} + + +void VerifyDiagnosticsClient::CheckDiagnostics() { + DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes; + + // Ensure any diagnostics go to the primary client. + DiagnosticClient *CurClient = Diags.getClient(); + Diags.setClient(PrimaryClient.get()); + + // If we have a preprocessor, scan the source for expected diagnostic + // markers. If not then any diagnostics are unexpected. + if (CurrentPreprocessor) { + FindExpectedDiags(*CurrentPreprocessor, ExpectedErrors, ExpectedWarnings, + ExpectedNotes); + + // Check that the expected diagnostics occurred. + NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(), + *Buffer, + ExpectedErrors, ExpectedWarnings, ExpectedNotes); + } 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)); + } + + Diags.setClient(CurClient); + + // Reset the buffer, we have processed all the diagnostics in it. + Buffer.reset(new TextDiagnosticBuffer()); +} diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index 7b01b0fb7416..ff44c9051663 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -24,6 +24,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include <cstdio> #include <cstring> @@ -32,26 +33,24 @@ using namespace clang; bool clang::ProcessWarningOptions(Diagnostic &Diags, - std::vector<std::string> &Warnings, - bool Pedantic, bool PedanticErrors, - bool NoWarnings) { + const DiagnosticOptions &Opts) { Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers - Diags.setIgnoreAllWarnings(NoWarnings); + Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); // If -pedantic or -pedantic-errors was specified, then we want to map all // extension diagnostics onto WARNING or ERROR unless the user has futz'd // around with them explicitly. - if (PedanticErrors) + if (Opts.PedanticErrors) Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error); - else if (Pedantic) + else if (Opts.Pedantic) Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn); else Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore); // FIXME: -Wfatal-errors / -Wfatal-errors=foo - for (unsigned i = 0, e = Warnings.size(); i != e; ++i) { - const std::string &Opt = Warnings[i]; + for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { + const std::string &Opt = Opts.Warnings[i]; const char *OptStart = &Opt[0]; const char *OptEnd = OptStart+Opt.size(); assert(*OptEnd == 0 && "Expect null termination for lower-bound search"); @@ -100,8 +99,7 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags, } if (Diags.setDiagnosticGroupMapping(OptStart, Mapping)) - Diags.Report(FullSourceLoc(), diag::warn_unknown_warning_option) - << ("-W" + Opt); + Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt); } return false; |