diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-12-15 18:49:47 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-12-15 18:49:47 +0000 |
commit | 34d02d0b37f16015f317a935c48ce8b7b64ae77b (patch) | |
tree | 2fd5819f49caecc5f520219b6b9254fe94ebb138 /lib/Frontend | |
parent | 1569ce68681d909594d64f9b056d71f5dd7563bf (diff) | |
download | src-34d02d0b37f16015f317a935c48ce8b7b64ae77b.tar.gz src-34d02d0b37f16015f317a935c48ce8b7b64ae77b.zip |
Notes
Diffstat (limited to 'lib/Frontend')
24 files changed, 861 insertions, 377 deletions
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 9a30f59465f8..f1a666646ff9 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -28,8 +28,6 @@ #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" -#include <cstdio> - using namespace clang; //===----------------------------------------------------------------------===// @@ -405,8 +403,13 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "<objc property> " << OPD->getNameAsString() << "\n"; break; } + case Decl::FunctionTemplate: { + FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I); + Out << "<function template> " << FTD->getNameAsString() << "\n"; + break; + } default: - fprintf(stderr, "DeclKind: %d \"%s\"\n", DK, I->getDeclKindName()); + Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n"; assert(0 && "decl unhandled"); } } diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index f647c8a23705..48296c7289e3 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -17,27 +17,29 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Job.h" +#include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.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/LLVMContext.h" +#include "llvm/System/Host.h" #include "llvm/System/Path.h" using namespace clang; -ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) { - Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer()); +ASTUnit::ASTUnit(bool _MainFileIsAST) + : tempFile(false), MainFileIsAST(_MainFileIsAST) { } ASTUnit::~ASTUnit() { if (tempFile) llvm::sys::Path(getPCHFileName()).eraseFromDisk(); - - // The ASTUnit object owns the DiagnosticClient. - delete Diags.getClient(); } namespace { @@ -90,19 +92,19 @@ public: } // anonymous namespace const std::string &ASTUnit::getOriginalSourceFileName() { - return dyn_cast<PCHReader>(Ctx->getExternalSource())->getOriginalSourceFile(); + return OriginalSourceFile; } const std::string &ASTUnit::getPCHFileName() { + assert(isMainFileAST() && "Not an ASTUnit from a PCH file!"); return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName(); } ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, - std::string *ErrMsg, - DiagnosticClient *diagClient, + Diagnostic &Diags, bool OnlyLocalDecls, bool UseBumpAllocator) { - llvm::OwningPtr<ASTUnit> AST(new ASTUnit(diagClient)); + llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); AST->OnlyLocalDecls = OnlyLocalDecls; AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); @@ -118,7 +120,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, llvm::OwningPtr<ExternalASTSource> Source; Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(), - AST->Diags)); + Diags)); Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple, Predefines, Counter)); @@ -128,11 +130,12 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, case PCHReader::Failure: case PCHReader::IgnorePCH: - if (ErrMsg) - *ErrMsg = "Could not load PCH file"; + Diags.Report(diag::err_fe_unable_to_load_pch); return NULL; } + AST->OriginalSourceFile = Reader->getOriginalSourceFile(); + // PCH loaded successfully. Now create the preprocessor. // Get information about the target being compiled for. @@ -143,8 +146,8 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, 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->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts)); + AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(), AST->getSourceManager(), HeaderInfo)); Preprocessor &PP = *AST->PP.get(); @@ -177,13 +180,30 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, namespace { -class NullAction : public ASTFrontendAction { +class TopLevelDeclTrackerConsumer : public ASTConsumer { + ASTUnit &Unit; + +public: + TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {} + + void HandleTopLevelDecl(DeclGroupRef D) { + for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) + Unit.getTopLevelDecls().push_back(*it); + } +}; + +class TopLevelDeclTrackerAction : public ASTFrontendAction { +public: + ASTUnit &Unit; + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return new ASTConsumer(); + return new TopLevelDeclTrackerConsumer(Unit); } public: + TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {} + virtual bool hasCodeCompletionSupport() const { return false; } }; @@ -191,12 +211,11 @@ public: ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, Diagnostic &Diags, - bool OnlyLocalDecls, - bool UseBumpAllocator) { + bool OnlyLocalDecls) { // Create the compiler instance to use for building the AST. - CompilerInstance Clang(&llvm::getGlobalContext(), false); + CompilerInstance Clang; llvm::OwningPtr<ASTUnit> AST; - NullAction Act; + llvm::OwningPtr<TopLevelDeclTrackerAction> Act; Clang.getInvocation() = CI; @@ -221,9 +240,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, "FIXME: AST inputs not yet supported here!"); // Create the AST unit. - // - // FIXME: Use the provided diagnostic client. - AST.reset(new ASTUnit()); + AST.reset(new ASTUnit(false)); + + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; // Create a file manager object to provide access to and cache the filesystem. Clang.setFileManager(&AST->getFileManager()); @@ -234,20 +254,22 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, // Create the preprocessor. Clang.createPreprocessor(); - if (!Act.BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, + Act.reset(new TopLevelDeclTrackerAction(*AST)); + if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, /*IsAST=*/false)) goto error; - Act.Execute(); + Act->Execute(); - // Steal the created context and preprocessor, and take back the source and - // file managers. + // Steal the created target, context, and preprocessor, and take back the + // source and file managers. AST->Ctx.reset(Clang.takeASTContext()); AST->PP.reset(Clang.takePreprocessor()); Clang.takeSourceManager(); Clang.takeFileManager(); + AST->Target.reset(Clang.takeTarget()); - Act.EndSourceFile(); + Act->EndSourceFile(); Clang.takeDiagnosticClient(); Clang.takeDiagnostics(); @@ -261,3 +283,53 @@ error: Clang.takeDiagnostics(); return 0; } + +ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, + const char **ArgEnd, + Diagnostic &Diags, + llvm::StringRef ResourceFilesPath, + bool OnlyLocalDecls, + bool UseBumpAllocator) { + llvm::SmallVector<const char *, 16> Args; + Args.push_back("<clang>"); // FIXME: Remove dummy argument. + Args.insert(Args.end(), ArgBegin, ArgEnd); + + // FIXME: Find a cleaner way to force the driver into restricted modes. We + // also want to force it to use clang. + Args.push_back("-fsyntax-only"); + + // FIXME: We shouldn't have to pass in the path info. + driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(), + "a.out", false, Diags); + llvm::OwningPtr<driver::Compilation> C( + TheDriver.BuildCompilation(Args.size(), Args.data())); + + // We expect to get back exactly one command job, if we didn't something + // failed. + const driver::JobList &Jobs = C->getJobs(); + if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) { + llvm::SmallString<256> Msg; + llvm::raw_svector_ostream OS(Msg); + C->PrintJob(OS, C->getJobs(), "; ", true); + Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); + return 0; + } + + const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin()); + if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { + Diags.Report(diag::err_fe_expected_clang_command); + return 0; + } + + const driver::ArgStringList &CCArgs = Cmd->getArguments(); + CompilerInvocation CI; + CompilerInvocation::CreateFromArgs(CI, (const char**) CCArgs.data(), + (const char**) CCArgs.data()+CCArgs.size(), + Diags); + + // Override the resources path. + CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath; + + CI.getFrontendOpts().DisableFree = UseBumpAllocator; + return LoadFromCompilerInvocation(CI, Diags, OnlyLocalDecls); +} diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 5df1eceb8850..a74bbc24ee10 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -139,13 +139,17 @@ public: return; declDisplayed = true; - // FIXME: Is getCodeDecl() always a named decl? + SourceManager &SM = Mgr->getASTContext().getSourceManager(); + PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); + llvm::errs() << "ANALYZE: " << Loc.getFilename(); + 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'; + llvm::errs() << ' ' << ND->getNameAsString() << '\n'; + } + else if (isa<BlockDecl>(D)) { + llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" + << Loc.getColumn() << '\n'; } } @@ -167,7 +171,6 @@ public: Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), PP.getLangOptions(), PD, CreateStoreMgr, CreateConstraintMgr, - Opts.AnalyzerDisplayProgress, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, Opts.PurgeDead, Opts.EagerlyAssume, Opts.TrimGraph)); @@ -265,10 +268,21 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { // Explicitly destroy the PathDiagnosticClient. This will flush its output. // FIXME: This should be replaced with something that doesn't rely on - // side-effects in PathDiagnosticClient's destructor. + // side-effects in PathDiagnosticClient's destructor. This is required when + // used with option -disable-free. Mgr.reset(NULL); } +static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { + if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) + WL.push_back(BD); + + for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); + I!=E; ++I) + if (DeclContext *DC = dyn_cast<DeclContext>(*I)) + FindBlocks(DC, WL); +} + void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { // Don't run the actions if an error has occured with parsing the file. @@ -285,8 +299,16 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { Mgr->ClearContexts(); // Dispatch on the actions. + llvm::SmallVector<Decl*, 10> WL; + WL.push_back(D); + + if (Body && Opts.AnalyzeNestedBlocks) + FindBlocks(cast<DeclContext>(D), WL); + for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) - (*I)(*this, *Mgr, D); + for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); + WI != WE; ++WI) + (*I)(*this, *Mgr, *WI); } //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp index 9dc109da65ef..9be6786b5f75 100644 --- a/lib/Frontend/Backend.cpp +++ b/lib/Frontend/Backend.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/CodeGenOptions.h" #include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/PassManager.h" @@ -31,12 +32,14 @@ #include "llvm/Target/SubtargetFeature.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegistry.h" using namespace clang; using namespace llvm; namespace { class BackendConsumer : public ASTConsumer { + Diagnostic &Diags; BackendAction Action; const CodeGenOptions &CodeGenOpts; const LangOptions &LangOpts; @@ -64,21 +67,20 @@ namespace { void CreatePasses(); - /// AddEmitPasses - Add passes necessary to emit assembly or LLVM - /// IR. + /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR. /// - /// \return True on success. On failure \arg Error will be set to - /// a user readable error message. - bool AddEmitPasses(std::string &Error); + /// \return True on success. + bool AddEmitPasses(); void EmitAssembly(); public: - BackendConsumer(BackendAction action, Diagnostic &Diags, + BackendConsumer(BackendAction action, Diagnostic &_Diags, const LangOptions &langopts, const CodeGenOptions &compopts, const TargetOptions &targetopts, bool TimePasses, const std::string &infile, llvm::raw_ostream *OS, LLVMContext& C) : + Diags(_Diags), Action(action), CodeGenOpts(compopts), LangOpts(langopts), @@ -195,7 +197,7 @@ FunctionPassManager *BackendConsumer::getPerFunctionPasses() const { return PerFunctionPasses; } -bool BackendConsumer::AddEmitPasses(std::string &Error) { +bool BackendConsumer::AddEmitPasses() { if (Action == Backend_EmitNothing) return true; @@ -207,48 +209,68 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { bool Fast = CodeGenOpts.OptimizationLevel == 0; // Create the TargetMachine for generating code. + std::string Error; std::string Triple = TheModule->getTargetTriple(); const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); if (!TheTarget) { - Error = std::string("Unable to get target machine: ") + Error; + Diags.Report(diag::err_fe_unable_to_create_target) << Error; return false; } // FIXME: Expose these capabilities via actual APIs!!!! Aside from just // being gross, this is also totally broken if we ever care about // concurrency. + llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim; + if (CodeGenOpts.FloatABI == "soft") + llvm::FloatABIType = llvm::FloatABI::Soft; + else if (CodeGenOpts.FloatABI == "hard") + llvm::FloatABIType = llvm::FloatABI::Hard; + else { + assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!"); + llvm::FloatABIType = llvm::FloatABI::Default; + } + NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; + llvm::UseSoftFloat = CodeGenOpts.SoftFloat; + UnwindTablesMandatory = CodeGenOpts.UnwindTables; + + TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); + + // FIXME: Parse this earlier. + if (CodeGenOpts.RelocationModel == "static") { + TargetMachine::setRelocationModel(llvm::Reloc::Static); + } else if (CodeGenOpts.RelocationModel == "pic") { + TargetMachine::setRelocationModel(llvm::Reloc::PIC_); + } else { + assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && + "Invalid PIC model!"); + TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC); + } + // FIXME: Parse this earlier. + if (CodeGenOpts.CodeModel == "small") { + TargetMachine::setCodeModel(llvm::CodeModel::Small); + } else if (CodeGenOpts.CodeModel == "kernel") { + TargetMachine::setCodeModel(llvm::CodeModel::Kernel); + } else if (CodeGenOpts.CodeModel == "medium") { + TargetMachine::setCodeModel(llvm::CodeModel::Medium); + } else if (CodeGenOpts.CodeModel == "large") { + TargetMachine::setCodeModel(llvm::CodeModel::Large); + } else { + assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); + TargetMachine::setCodeModel(llvm::CodeModel::Default); + } + std::vector<const char *> BackendArgs; BackendArgs.push_back("clang"); // Fake program name. - if (CodeGenOpts.AsmVerbose) - BackendArgs.push_back("-asm-verbose"); - if (!CodeGenOpts.CodeModel.empty()) { - BackendArgs.push_back("-code-model"); - BackendArgs.push_back(CodeGenOpts.CodeModel.c_str()); - } if (!CodeGenOpts.DebugPass.empty()) { BackendArgs.push_back("-debug-pass"); BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); } - if (CodeGenOpts.DisableFPElim) - BackendArgs.push_back("-disable-fp-elim"); - if (!CodeGenOpts.FloatABI.empty()) { - BackendArgs.push_back("-float-abi"); - BackendArgs.push_back(CodeGenOpts.FloatABI.c_str()); - } if (!CodeGenOpts.LimitFloatPrecision.empty()) { BackendArgs.push_back("-limit-float-precision"); BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); } - if (CodeGenOpts.NoZeroInitializedInBSS) - BackendArgs.push_back("-nozero-initialized-in-bss"); - if (CodeGenOpts.SoftFloat) - BackendArgs.push_back("-soft-float"); - BackendArgs.push_back("-relocation-model"); - BackendArgs.push_back(CodeGenOpts.RelocationModel.c_str()); if (llvm::TimePassesIsEnabled) BackendArgs.push_back("-time-passes"); - if (CodeGenOpts.UnwindTables) - BackendArgs.push_back("-unwind-tables"); BackendArgs.push_back(0); llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, (char**) &BackendArgs[0]); @@ -290,7 +312,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { TargetMachine::AssemblyFile, OptLevel)) { default: case FileModel::Error: - Error = "Unable to interface with target machine!\n"; + Diags.Report(diag::err_fe_unable_to_interface_with_target); return false; case FileModel::AsmFile: break; @@ -298,7 +320,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0, OptLevel)) { - Error = "Unable to interface with target machine!\n"; + Diags.Report(diag::err_fe_unable_to_interface_with_target); return false; } } @@ -329,8 +351,14 @@ void BackendConsumer::CreatePasses() { switch (Inlining) { case CodeGenOptions::NoInlining: break; case CodeGenOptions::NormalInlining: { - // Inline small functions - unsigned Threshold = (CodeGenOpts.OptimizeSize || OptLevel < 3) ? 50 : 200; + // Set the inline threshold following llvm-gcc. + // + // FIXME: Derive these constants in a principled fashion. + unsigned Threshold = 200; + if (CodeGenOpts.OptimizeSize) + Threshold = 50; + else if (OptLevel > 2) + Threshold = 250; InliningPass = createFunctionInliningPass(Threshold); break; } @@ -372,13 +400,8 @@ void BackendConsumer::EmitAssembly() { assert(TheModule == M && "Unexpected module change during IR generation"); CreatePasses(); - - std::string Error; - if (!AddEmitPasses(Error)) { - // FIXME: Don't fail this way. - llvm::errs() << "ERROR: " << Error << "\n"; - ::exit(1); - } + if (!AddEmitPasses()) + return; // Run passes. For now we do all passes at once, but eventually we // would like to have the option of streaming code generation. diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 1083d5ef1c02..2a6a8a8750d2 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -95,7 +95,7 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, return; } - (*OS) << "clang-cc command line arguments: "; + (*OS) << "clang -cc1 command line arguments: "; for (unsigned i = 0; i != argc; ++i) (*OS) << argv[i] << ' '; (*OS) << '\n'; @@ -172,10 +172,6 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, 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, @@ -287,7 +283,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, } // Truncate the named file at the given line/column. - PP.getSourceManager().truncateFileAt(Entry, Line, Column); + PP.SetCodeCompletionPoint(Entry, Line, Column); // Set up the creation routine for code-completion. if (UseDebugPrinter) @@ -332,9 +328,9 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, InFile, Extension, &OutputPathName); if (!OS) { - // FIXME: Don't fail this way. - llvm::errs() << "error: " << Error << "\n"; - ::exit(1); + getDiagnostics().Report(diag::err_fe_unable_to_open_output) + << OutputPath << Error; + return 0; } // Add the output file -- but don't try to remove "-", since this means we are diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index c5375079506b..7a3388ffbb97 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -31,7 +31,7 @@ using namespace clang; static const char *getAnalysisName(Analyses Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis store!"); + llvm_unreachable("Unknown analysis kind!"); #define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\ case NAME: return "-" CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -41,7 +41,7 @@ static const char *getAnalysisName(Analyses Kind) { static const char *getAnalysisStoreName(AnalysisStores Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis store!"); + llvm_unreachable("Unknown analysis store!"); #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ case NAME##Model: return CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -51,7 +51,7 @@ static const char *getAnalysisStoreName(AnalysisStores Kind) { static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis constraints!"); + llvm_unreachable("Unknown analysis constraints!"); #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ case NAME##Model: return CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -61,7 +61,7 @@ static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis client!"); + llvm_unreachable("Unknown analysis client!"); #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \ case PD_##NAME: return CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -96,6 +96,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-opt-analyze-headers"); if (Opts.AnalyzerDisplayProgress) Res.push_back("-analyzer-display-progress"); + if (Opts.AnalyzeNestedBlocks) + Res.push_back("-analyzer-opt-analyze-nested-blocks"); if (Opts.EagerlyAssume) Res.push_back("-analyzer-eagerly-assume"); if (!Opts.PurgeDead) @@ -244,7 +246,7 @@ static const char *getInputKindName(FrontendOptions::InputKind Kind) { case FrontendOptions::IK_PreprocessedObjCXX:return "objective-c++-cpp-output"; } - llvm::llvm_unreachable("Unexpected language kind!"); + llvm_unreachable("Unexpected language kind!"); return 0; } @@ -252,7 +254,7 @@ static const char *getActionName(frontend::ActionKind Kind) { switch (Kind) { case frontend::PluginAction: case frontend::InheritanceView: - llvm::llvm_unreachable("Invalid kind!"); + llvm_unreachable("Invalid kind!"); case frontend::ASTDump: return "-ast-dump"; case frontend::ASTPrint: return "-ast-print"; @@ -282,7 +284,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::RunPreprocessorOnly: return "-Eonly"; } - llvm::llvm_unreachable("Unexpected language kind!"); + llvm_unreachable("Unexpected language kind!"); return 0; } @@ -296,12 +298,16 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-empty-input-only"); if (Opts.RelocatablePCH) Res.push_back("-relocatable-pch"); + if (Opts.ShowHelp) + Res.push_back("-help"); if (Opts.ShowMacrosInCodeCompletion) Res.push_back("-code-completion-macros"); if (Opts.ShowStats) Res.push_back("-print-stats"); if (Opts.ShowTimers) Res.push_back("-ftime-report"); + if (Opts.ShowVersion) + Res.push_back("-version"); bool NeedLang = false; for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) @@ -345,6 +351,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-plugin"); Res.push_back(Opts.ActionName); } + for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) { + Res.push_back("-load"); + Res.push_back(Opts.Plugins[i]); + } } static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, @@ -399,8 +409,9 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, // 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.ResourceDir.empty()) { + Res.push_back("-resource-dir"); + Res.push_back(Opts.ResourceDir); } if (!Opts.UseStandardIncludes) Res.push_back("-nostdinc"); @@ -437,6 +448,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fno-operator-names"); if (Opts.PascalStrings) Res.push_back("-fpascal-strings"); + if (Opts.CatchUndefined) + Res.push_back("-fcatch-undefined-behavior"); if (Opts.WritableStrings) Res.push_back("-fwritable-strings"); if (!Opts.LaxVectorConversions) @@ -445,7 +458,7 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-faltivec"); if (Opts.Exceptions) Res.push_back("-fexceptions"); - if (!Opts.Rtti) + if (!Opts.RTTI) Res.push_back("-fno-rtti"); if (!Opts.NeXTRuntime) Res.push_back("-fgnu-runtime"); @@ -550,6 +563,11 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, assert(Opts.ImplicitPTHInclude == Opts.TokenCache && "Unsupported option combination!"); } + for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) { + Res.push_back("-remap-file"); + Res.push_back(Opts.RemappedFiles[i].first + ";" + + Opts.RemappedFiles[i].second); + } } static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, @@ -696,6 +714,8 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); + Opts.AnalyzeNestedBlocks = + Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); Opts.AnalyzeSpecificFunction = getLastArgValue(Args, OPT_analyze_function); @@ -877,10 +897,13 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { } Opts.OutputFile = getLastArgValue(Args, OPT_o); + Opts.Plugins = getAllArgValues(Args, OPT_load); Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); + Opts.ShowHelp = Args.hasArg(OPT_help); Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); Opts.ShowStats = Args.hasArg(OPT_print_stats); Opts.ShowTimers = Args.hasArg(OPT_ftime_report); + Opts.ShowVersion = Args.hasArg(OPT_version); Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view); FrontendOptions::InputKind DashX = FrontendOptions::IK_None; @@ -929,8 +952,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { return DashX; } -static std::string GetBuiltinIncludePath(const char *Argv0, - void *MainAddr) { +std::string CompilerInvocation::GetResourcesPath(const char *Argv0, + void *MainAddr) { llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr); if (!P.isEmpty()) { @@ -941,22 +964,18 @@ static std::string GetBuiltinIncludePath(const char *Argv0, P.appendComponent("lib"); P.appendComponent("clang"); P.appendComponent(CLANG_VERSION_STRING); - P.appendComponent("include"); } return P.str(); } -static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, - const char *Argv0, void *MainAddr) { +static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { using namespace cc1options; Opts.Sysroot = getLastArgValue(Args, OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); + Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc); - Opts.BuiltinIncludePath = ""; - // FIXME: Add an option for this, its a slow call. - if (!Args.hasArg(OPT_nobuiltininc)) - Opts.BuiltinIncludePath = GetBuiltinIncludePath(Argv0, MainAddr); + Opts.ResourceDir = getLastArgValue(Args, OPT_resource_dir); // Add -I... and -F... options in order. for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F), @@ -1115,7 +1134,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_fno_lax_vector_conversions)) Opts.LaxVectorConversions = 0; Opts.Exceptions = Args.hasArg(OPT_fexceptions); - Opts.Rtti = !Args.hasArg(OPT_fno_rtti); + Opts.RTTI = !Args.hasArg(OPT_fno_rtti); Opts.Blocks = Args.hasArg(OPT_fblocks); Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); @@ -1131,6 +1150,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.ObjCConstantStringClass = getLastArgValue(Args, OPT_fconstant_string_class); Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); + Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); Opts.Static = Args.hasArg(OPT_static_define); @@ -1160,7 +1180,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, } } -static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) { +static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, + Diagnostic &Diags) { using namespace cc1options; Opts.ImplicitPCHInclude = getLastArgValue(Args, OPT_include_pch); Opts.ImplicitPTHInclude = getLastArgValue(Args, OPT_include_pth); @@ -1188,16 +1209,27 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) { // PCH is handled specially, we need to extra the original include path. if (it->getOption().matches(OPT_include_pch)) { std::string OriginalFile = - PCHReader::getOriginalSourceFile(it->getValue(Args)); - - // FIXME: Don't fail like this. + PCHReader::getOriginalSourceFile(it->getValue(Args), Diags); if (OriginalFile.empty()) - exit(1); + continue; Opts.Includes.push_back(OriginalFile); } else Opts.Includes.push_back(it->getValue(Args)); } + + for (arg_iterator it = Args.filtered_begin(OPT_remap_file), + ie = Args.filtered_end(); it != ie; ++it) { + std::pair<llvm::StringRef,llvm::StringRef> Split = + llvm::StringRef(it->getValue(Args)).split(';'); + + if (Split.second.empty()) { + Diags.Report(diag::err_drv_invalid_remap_file) << it->getAsString(Args); + continue; + } + + Opts.addRemappedFile(Split.first, Split.second); + } } static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, @@ -1227,8 +1259,6 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, const char **ArgBegin, const char **ArgEnd, - const char *Argv0, - void *MainAddr, Diagnostic &Diags) { // Parse the arguments. llvm::OwningPtr<OptTable> Opts(createCC1OptTable()); @@ -1252,11 +1282,10 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags); FrontendOptions::InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); - ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args, - Argv0, MainAddr); + ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args); if (DashX != FrontendOptions::IK_AST) ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags); - ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args); + ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, Diags); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); ParseTargetArgs(Res.getTargetOpts(), *Args); } diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp index e7a66b1729c4..a50cc99ab79e 100644 --- a/lib/Frontend/DiagChecker.cpp +++ b/lib/Frontend/DiagChecker.cpp @@ -17,7 +17,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" -#include <cstdio> +#include "llvm/Support/raw_ostream.h" using namespace clang; typedef TextDiagnosticBuffer::DiagList DiagList; @@ -190,12 +190,10 @@ static bool PrintProblem(SourceManager &SourceMgr, const char *Msg) { if (diag_begin == diag_end) return false; - fprintf(stderr, "%s\n", Msg); - + llvm::errs() << Msg << "\n"; for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) - fprintf(stderr, " Line %d: %s\n", - SourceMgr.getInstantiationLineNumber(I->first), - I->second.c_str()); + llvm::errs() << " Line " << SourceMgr.getInstantiationLineNumber(I->first) + << " " << I->second << "\n"; return true; } diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp index dddcaa97e2ff..4fa2b3c51eb5 100644 --- a/lib/Frontend/FixItRewriter.cpp +++ b/lib/Frontend/FixItRewriter.cpp @@ -66,7 +66,7 @@ bool FixItRewriter::WriteFixedFile(const std::string &InFileName, Rewrite.getRewriteBufferFor(MainFileID)) { *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); } else { - std::fprintf(stderr, "Main file is unchanged\n"); + Diag(FullSourceLoc(), diag::note_fixit_main_file_unchanged); } OutFile->flush(); diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 91c946c9cf25..96a68c931e1f 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -46,11 +46,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, 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; + ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, CI.getDiagnostics()); + if (!AST) goto failure; - } setCurrentFile(Filename, AST); @@ -224,5 +222,5 @@ void ASTFrontendAction::ExecuteAction() { ASTConsumer * PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - llvm::llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); + llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); } diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 27e194e6f108..e3c313a42299 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -35,13 +35,16 @@ ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI, ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateASTPrinter(CI.createDefaultOutputFile(false, InFile)); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + return CreateASTPrinter(OS); + return 0; } ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateASTPrinterXML(CI.createDefaultOutputFile(false, InFile, - "xml")); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml")) + return CreateASTPrinterXML(OS); + return 0; } ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, @@ -74,6 +77,9 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, } llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); + if (!OS) + return 0; + if (CI.getFrontendOpts().RelocatablePCH) return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str()); @@ -82,8 +88,9 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateHTMLPrinter(CI.createDefaultOutputFile(false, InFile), - CI.getPreprocessor()); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + return CreateHTMLPrinter(OS, CI.getPreprocessor()); + return 0; } ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, @@ -140,10 +147,11 @@ void FixItAction::EndSourceFileAction() { ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateObjCRewriter(InFile, - CI.createDefaultOutputFile(true, InFile, "cpp"), - CI.getDiagnostics(), CI.getLangOpts(), - CI.getDiagnosticOpts().NoRewriteMacros); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) + return CreateObjCRewriter(InFile, OS, + CI.getDiagnostics(), CI.getLangOpts(), + CI.getDiagnosticOpts().NoRewriteMacros); + return 0; } ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI, @@ -162,12 +170,21 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { BackendAction BA = static_cast<BackendAction>(Act); llvm::OwningPtr<llvm::raw_ostream> OS; - if (BA == Backend_EmitAssembly) + switch (BA) { + case Backend_EmitAssembly: OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); - else if (BA == Backend_EmitLL) + break; + case Backend_EmitLL: OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); - else if (BA == Backend_EmitBC) + break; + case Backend_EmitBC: OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); + break; + case Backend_EmitNothing: + break; + } + if (BA != Backend_EmitNothing && !OS) + return 0; return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(), @@ -228,6 +245,8 @@ void GeneratePTHAction::ExecuteAction() { } llvm::raw_fd_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + CacheTokens(CI.getPreprocessor(), OS); } @@ -255,6 +274,8 @@ void PrintParseAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); Preprocessor &PP = getCompilerInstance().getPreprocessor(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS)); Parser P(PP, *PA); @@ -265,6 +286,8 @@ void PrintParseAction::ExecuteAction() { void PrintPreprocessedAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + DoPrintPreprocessedInput(CI.getPreprocessor(), OS, CI.getPreprocessorOutputOpts()); } @@ -272,11 +295,15 @@ void PrintPreprocessedAction::ExecuteAction() { void RewriteMacrosAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + RewriteMacrosInInput(CI.getPreprocessor(), OS); } void RewriteTestAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + DoRewriteTest(CI.getPreprocessor(), OS); } diff --git a/lib/Frontend/HTMLPrint.cpp b/lib/Frontend/HTMLPrint.cpp index 75e6184572e5..9ea8cb3feee6 100644 --- a/lib/Frontend/HTMLPrint.cpp +++ b/lib/Frontend/HTMLPrint.cpp @@ -41,9 +41,9 @@ namespace { bool _SyntaxHighlight, bool _HighlightMacros) : Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight), HighlightMacros(_HighlightMacros) {} - virtual ~HTMLPrinter(); void Initialize(ASTContext &context); + void HandleTranslationUnit(ASTContext &Ctx); }; } @@ -58,7 +58,7 @@ void HTMLPrinter::Initialize(ASTContext &context) { R.setSourceMgr(context.getSourceManager(), context.getLangOptions()); } -HTMLPrinter::~HTMLPrinter() { +void HTMLPrinter::HandleTranslationUnit(ASTContext &Ctx) { if (PP.getDiagnostics().hasErrorOccurred()) return; diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index a40a569d92f7..b4ea2576c3e6 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -21,10 +21,10 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/Config/config.h" -#include <cstdio> #ifdef _MSC_VER #define WIN32_LEAN_AND_MEAN 1 #include <windows.h> @@ -50,27 +50,27 @@ public: : Headers(HS), Verbose(verbose), isysroot(iSysroot) {} /// AddPath - Add the specified path to the specified group list. - void AddPath(const llvm::StringRef &Path, IncludeDirGroup Group, + void AddPath(const llvm::Twine &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, + void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef ArchDir, + llvm::StringRef Dir32, + llvm::StringRef 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); + void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef Arch, + llvm::StringRef Version); /// AddDelimitedPaths - Add a list of paths delimited by the system PATH /// separator. The processing follows that of the CPATH variable for gcc. - void AddDelimitedPaths(const char *String); + void AddDelimitedPaths(llvm::StringRef String); // AddDefaultCIncludePaths - Add paths that should always be searched. void AddDefaultCIncludePaths(const llvm::Triple &triple); @@ -91,25 +91,26 @@ public: } -void InitHeaderSearch::AddPath(const llvm::StringRef &Path, +void InitHeaderSearch::AddPath(const llvm::Twine &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot) { - assert(!Path.empty() && "can't handle empty path here"); + assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); FileManager &FM = Headers.getFileMgr(); // Compute the actual path, taking into consideration -isysroot. - llvm::SmallString<256> MappedPath; + llvm::SmallString<256> MappedPathStr; + llvm::raw_svector_ostream MappedPath(MappedPathStr); // Handle isysroot. if (Group == System && !IgnoreSysRoot) { // FIXME: Portability. This should be a sys::Path interface, this doesn't // handle things like C:\ right, nor win32 \\network\device\blah. if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present. - MappedPath.append(isysroot.begin(), isysroot.end()); + MappedPath << isysroot; } - MappedPath.append(Path.begin(), Path.end()); + Path.print(MappedPath); // Compute the DirectoryLookup type. SrcMgr::CharacteristicKind Type; @@ -146,29 +147,29 @@ void InitHeaderSearch::AddPath(const llvm::StringRef &Path, } -void InitHeaderSearch::AddDelimitedPaths(const char *at) { - if (*at == 0) // Empty string should not add '.' path. +void InitHeaderSearch::AddDelimitedPaths(llvm::StringRef at) { + if (at.empty()) // Empty string should not add '.' path. return; - const char* delim = strchr(at, llvm::sys::PathSeparator); - while (delim != 0) { - if (delim-at == 0) + llvm::StringRef::size_type delim; + while ((delim = at.find(llvm::sys::PathSeparator)) != llvm::StringRef::npos) { + if (delim == 0) AddPath(".", Angled, false, true, false); else - AddPath(llvm::StringRef(at, delim-at), Angled, false, true, false); - at = delim + 1; - delim = strchr(at, llvm::sys::PathSeparator); + AddPath(at.substr(0, delim), Angled, false, true, false); + at = at.substr(delim + 1); } - if (*at == 0) + + if (at.empty()) AddPath(".", Angled, false, true, false); else AddPath(at, Angled, false, true, false); } -void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base, - const char *ArchDir, - const char *Dir32, - const char *Dir64, +void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef ArchDir, + llvm::StringRef Dir32, + llvm::StringRef Dir64, const llvm::Triple &triple) { // Add the base dir AddPath(Base, System, true, false, false); @@ -185,10 +186,10 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base, AddPath(Base + "/backward", System, true, false, false); } -void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base, - const char *Arch, - const char *Version) { - std::string localBase = Base + "/" + Arch + "/" + Version + "/include"; +void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef Arch, + llvm::StringRef Version) { + llvm::Twine 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); @@ -258,25 +259,25 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName, int bestIndex = -1; double bestValue = 0.0; DWORD index, size = sizeof(keyName) - 1; - for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
- NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
- const char *sp = keyName;
- while (*sp && !isdigit(*sp))
- sp++;
- if (!*sp)
- continue;
- const char *ep = sp + 1;
- while (*ep && (isdigit(*ep) || (*ep == '.')))
- ep++;
- char numBuf[32];
- strncpy(numBuf, sp, sizeof(numBuf) - 1);
- numBuf[sizeof(numBuf) - 1] = '\0';
- double value = strtod(numBuf, NULL);
- if (value > bestValue) {
- bestIndex = (int)index;
- bestValue = value;
- strcpy(bestName, keyName);
- }
+ for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL, + NULL, NULL, NULL) == ERROR_SUCCESS; index++) { + const char *sp = keyName; + while (*sp && !isdigit(*sp)) + sp++; + if (!*sp) + continue; + const char *ep = sp + 1; + while (*ep && (isdigit(*ep) || (*ep == '.'))) + ep++; + char numBuf[32]; + strncpy(numBuf, sp, sizeof(numBuf) - 1); + numBuf[sizeof(numBuf) - 1] = '\0'; + double value = strtod(numBuf, NULL); + if (value > bestValue) { + bestIndex = (int)index; + bestValue = value; + strcpy(bestName, keyName); + } size = sizeof(keyName) - 1; } // If we found the highest versioned key, open the key and get the value. @@ -500,6 +501,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", "i586-redhat-linux","", "", triple); + // Fedora 12 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "i686-redhat-linux","", "", triple); + // openSUSE 11.1 32 bit AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", "i586-suse-linux", "", "", triple); @@ -643,11 +648,11 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, } if (Verbose) { - fprintf(stderr, "ignoring duplicate directory \"%s\"\n", - CurEntry.getName()); + llvm::errs() << "ignoring duplicate directory \"" + << CurEntry.getName() << "\"\n"; if (DirToRemove != i) - fprintf(stderr, " as it is a non-system directory that duplicates" - " a system directory\n"); + llvm::errs() << " as it is a non-system directory that duplicates " + << "a system directory\n"; } // This is reached if the current entry is a duplicate. Remove the @@ -680,11 +685,11 @@ void InitHeaderSearch::Realize() { // If verbose, print the list of directories that will be searched. if (Verbose) { - fprintf(stderr, "#include \"...\" search starts here:\n"); + llvm::errs() << "#include \"...\" search starts here:\n"; unsigned QuotedIdx = IncludeGroup[Quoted].size(); for (unsigned i = 0, e = SearchList.size(); i != e; ++i) { if (i == QuotedIdx) - fprintf(stderr, "#include <...> search starts here:\n"); + llvm::errs() << "#include <...> search starts here:\n"; const char *Name = SearchList[i].getName(); const char *Suffix; if (SearchList[i].isNormalDir()) @@ -695,9 +700,9 @@ void InitHeaderSearch::Realize() { assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup"); Suffix = " (headermap)"; } - fprintf(stderr, " %s%s\n", Name, Suffix); + llvm::errs() << " " << Name << Suffix << "\n"; } - fprintf(stderr, "End of search list.\n"); + llvm::errs() << "End of search list.\n"; } } @@ -715,21 +720,22 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, } // Add entries from CPATH and friends. - Init.AddDelimitedPaths(HSOpts.EnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.EnvIncPath); if (Lang.CPlusPlus && Lang.ObjC1) - Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath); else if (Lang.CPlusPlus) - Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath); else if (Lang.ObjC1) - Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath); else - Init.AddDelimitedPaths(HSOpts.CEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.CEnvIncPath); - if (!HSOpts.BuiltinIncludePath.empty()) { + if (HSOpts.UseBuiltinIncludes) { // Ignore the sys root, we *always* look for clang headers relative to // supplied path. - Init.AddPath(HSOpts.BuiltinIncludePath, System, - false, false, false, /*IgnoreSysRoot=*/ true); + llvm::sys::Path P(HSOpts.ResourceDir); + P.appendComponent("include"); + Init.AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true); } if (HSOpts.UseStandardIncludes) diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 972c21f88d4d..c1fc92d3b0c9 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -13,17 +13,23 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/PreprocessorOptions.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Path.h" using namespace clang; // Append a #define line to Buf for Macro. Macro should be of the form XXX, // in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit // "#define XXX Y z W". To get a #define with no value, use "XXX=". -static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) { +static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro, + Diagnostic *Diags = 0) { const char *Command = "#define "; Buf.insert(Buf.end(), Command, Command+strlen(Command)); if (const char *Equal = strchr(Macro, '=')) { @@ -34,9 +40,9 @@ static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) { // Per GCC -D semantics, the macro ends at \n if it exists. const char *End = strpbrk(Equal, "\n\r"); if (End) { - fprintf(stderr, "warning: macro '%s' contains embedded newline, text " - "after the newline is ignored.\n", - std::string(Macro, Equal).c_str()); + assert(Diags && "Unexpected macro with embedded newline!"); + Diags->Report(diag::warn_fe_macro_contains_embedded_newline) + << std::string(Macro, Equal); } else { End = Equal+strlen(Equal); } @@ -118,11 +124,9 @@ static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP, const char *OriginalFile = P->getOriginalSourceFile(); if (!OriginalFile) { - assert(!ImplicitIncludePTH.empty()); - fprintf(stderr, "error: PTH file '%s' does not designate an original " - "source header file for -include-pth\n", - ImplicitIncludePTH.c_str()); - exit (1); + PP.getDiagnostics().Report(diag::err_fe_pth_file_has_no_source_header) + << ImplicitIncludePTH; + return; } AddImplicitInclude(Buf, OriginalFile); @@ -358,6 +362,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__"); DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__"); DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__"); + // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however + // VC++ appears to only like __FUNCTION__. + DefineBuiltinMacro(Buf, "__PRETTY_FUNCTION__=__FUNCTION__"); // Work around some issues with Visual C++ headerws. if (LangOpts.CPlusPlus) { // Since we define wchar_t in C++ mode. @@ -478,6 +485,52 @@ static void InitializePredefinedMacros(const TargetInfo &TI, TI.getTargetDefines(LangOpts, Buf); } +// Initialize the remapping of files to alternative contents, e.g., +// those specified through other files. +static void InitializeFileRemapping(Diagnostic &Diags, + SourceManager &SourceMgr, + FileManager &FileMgr, + const PreprocessorOptions &InitOpts) { + // Remap files in the source manager. + for (PreprocessorOptions::remapped_file_iterator + Remap = InitOpts.remapped_file_begin(), + RemapEnd = InitOpts.remapped_file_end(); + Remap != RemapEnd; + ++Remap) { + // Find the file that we're mapping to. + const FileEntry *ToFile = FileMgr.getFile(Remap->second); + if (!ToFile) { + Diags.Report(diag::err_fe_remap_missing_to_file) + << Remap->first << Remap->second; + continue; + } + + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, + ToFile->getSize(), + 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) + << Remap->first; + continue; + } + + // Load the contents of the file we're mapping to. + std::string ErrorStr; + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); + if (!Buffer) { + Diags.Report(diag::err_fe_error_opening) + << Remap->second << ErrorStr; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, Buffer); + } +} + /// InitializePreprocessor - Initialize the preprocessor getting it and the /// environment ready to process a single file. This returns true on error. /// @@ -486,6 +539,9 @@ void clang::InitializePreprocessor(Preprocessor &PP, const HeaderSearchOptions &HSOpts) { std::vector<char> PredefineBuffer; + InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), + PP.getFileManager(), InitOpts); + const char *LineDirective = "# 1 \"<built-in>\" 3\n"; PredefineBuffer.insert(PredefineBuffer.end(), LineDirective, LineDirective+strlen(LineDirective)); @@ -506,7 +562,8 @@ void clang::InitializePreprocessor(Preprocessor &PP, if (InitOpts.Macros[i].second) // isUndef UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); else - DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); + DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str(), + &PP.getDiagnostics()); } // If -imacros are specified, include them now. These are processed before @@ -523,6 +580,11 @@ void clang::InitializePreprocessor(Preprocessor &PP, AddImplicitInclude(PredefineBuffer, Path); } + // Exit the command line and go back to <built-in> (2 is LC_LEAVE). + LineDirective = "# 1 \"<built-in>\" 2\n"; + PredefineBuffer.insert(PredefineBuffer.end(), + LineDirective, LineDirective+strlen(LineDirective)); + // Null terminate PredefinedBuffer and add it. PredefineBuffer.push_back(0); PP.setPredefines(&PredefineBuffer[0]); diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp index 771a58c60501..ed0ea1f45ef6 100644 --- a/lib/Frontend/LangStandards.cpp +++ b/lib/Frontend/LangStandards.cpp @@ -14,13 +14,13 @@ using namespace clang; using namespace clang::frontend; #define LANGSTANDARD(id, name, desc, features) \ - static LangStandard Lang_##id = { name, desc, features }; + static const LangStandard Lang_##id = { name, desc, features }; #include "clang/Frontend/LangStandards.def" const LangStandard &LangStandard::getLangStandardForKind(Kind K) { switch (K) { default: - llvm::llvm_unreachable("Invalid language kind!"); + llvm_unreachable("Invalid language kind!"); case lang_unspecified: llvm::llvm_report_error("getLangStandardForKind() on unspecified kind"); #define LANGSTANDARD(id, name, desc, features) \ diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index cb96bcb48aec..48ef2ac31aba 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -116,6 +116,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { diag::warn_pch_stack_protector); PARSE_LANGOPT_BENIGN(InstantiationDepth); PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl); + PARSE_LANGOPT_BENIGN(CatchUndefined); PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors); #undef PARSE_LANGOPT_IRRELEVANT #undef PARSE_LANGOPT_BENIGN @@ -1569,13 +1570,14 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { /// \brief Retrieve the name of the original source file name /// directly from the PCH file, without actually loading the PCH /// file. -std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { +std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName, + Diagnostic &Diags) { // Open the PCH file. std::string ErrStr; llvm::OwningPtr<llvm::MemoryBuffer> Buffer; Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr)); if (!Buffer) { - fprintf(stderr, "error: %s\n", ErrStr.c_str()); + Diags.Report(diag::err_fe_unable_to_read_pch_file) << ErrStr; return std::string(); } @@ -1591,9 +1593,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { Stream.Read(8) != 'P' || Stream.Read(8) != 'C' || Stream.Read(8) != 'H') { - fprintf(stderr, - "error: '%s' does not appear to be a precompiled header file\n", - PCHFileName.c_str()); + Diags.Report(diag::err_fe_not_a_pch_file) << PCHFileName; return std::string(); } @@ -1608,14 +1608,14 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { switch (BlockID) { case pch::PCH_BLOCK_ID: if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { - fprintf(stderr, "error: malformed block record in PCH file\n"); + Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName; return std::string(); } break; default: if (Stream.SkipBlock()) { - fprintf(stderr, "error: malformed block record in PCH file\n"); + Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName; return std::string(); } break; @@ -1625,7 +1625,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { if (Code == llvm::bitc::END_BLOCK) { if (Stream.ReadBlockEnd()) { - fprintf(stderr, "error: error at end of module block in PCH file\n"); + Diags.Report(diag::err_fe_pch_error_at_end_block) << PCHFileName; return std::string(); } continue; @@ -1720,6 +1720,8 @@ bool PCHReader::ParseLanguageOptions( ++Idx; PARSE_LANGOPT(InstantiationDepth); PARSE_LANGOPT(OpenCL); + PARSE_LANGOPT(CatchUndefined); + // FIXME: Missing ElideConstructors?! #undef PARSE_LANGOPT return Listener->ReadLanguageOptions(LangOpts); @@ -1881,6 +1883,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { Exceptions.data()); } + case pch::TYPE_UNRESOLVED_USING: + return Context->getTypeDeclType( + cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0]))); + case pch::TYPE_TYPEDEF: assert(Record.size() == 1 && "incorrect encoding of typedef type"); return Context->getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0]))); @@ -2045,6 +2051,9 @@ void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } +void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } @@ -2107,17 +2116,17 @@ void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); } -DeclaratorInfo *PCHReader::GetDeclaratorInfo(const RecordData &Record, +TypeSourceInfo *PCHReader::GetTypeSourceInfo(const RecordData &Record, unsigned &Idx) { QualType InfoTy = GetType(Record[Idx++]); if (InfoTy.isNull()) return 0; - DeclaratorInfo *DInfo = getContext()->CreateDeclaratorInfo(InfoTy); + TypeSourceInfo *TInfo = getContext()->CreateTypeSourceInfo(InfoTy); TypeLocReader TLR(*this, Record, Idx); - for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) TLR.Visit(TL); - return DInfo; + return TInfo; } QualType PCHReader::GetType(pch::TypeID ID) { @@ -2183,7 +2192,7 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, case TemplateArgument::Expression: return ReadDeclExpr(); case TemplateArgument::Type: - return GetDeclaratorInfo(Record, Index); + return GetTypeSourceInfo(Record, Index); case TemplateArgument::Template: { SourceLocation QualStart = SourceLocation::getFromRawEncoding(Record[Index++]), @@ -2198,7 +2207,7 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, case TemplateArgument::Pack: return TemplateArgumentLocInfo(); } - llvm::llvm_unreachable("unexpected template argument loc"); + llvm_unreachable("unexpected template argument loc"); return TemplateArgumentLocInfo(); } diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 03f3b4767994..01e1a4191a99 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -107,7 +107,7 @@ void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) { // the type associated with the TypedefDecl. VisitNamedDecl(TD); uint64_t TypeData = Record[Idx++]; - TD->setTypeDeclaratorInfo(Reader.GetDeclaratorInfo(Record, Idx)); + TD->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); TD->setTypeForDecl(Reader.GetType(TypeData).getTypePtr()); } @@ -126,6 +126,7 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) { void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) { VisitTagDecl(ED); ED->setIntegerType(Reader.GetType(Record[Idx++])); + ED->setPromotionType(Reader.GetType(Record[Idx++])); // FIXME: C++ InstantiatedFrom } @@ -150,9 +151,9 @@ void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { VisitValueDecl(DD); - DeclaratorInfo *DInfo = Reader.GetDeclaratorInfo(Record, Idx); - if (DInfo) - DD->setDeclaratorInfo(DInfo); + TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx); + if (TInfo) + DD->setTypeSourceInfo(TInfo); } void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 00734a0854a4..f28e61e1ecdc 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -349,7 +349,7 @@ unsigned PCHStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { unsigned PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); - E->setDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); + E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++]))); E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); // FIXME: read qualifier // FIXME: read explicit template arguments @@ -428,7 +428,7 @@ unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { E->setArgument(cast<Expr>(StmtStack.back())); ++Idx; } else { - E->setArgument(Reader.GetDeclaratorInfo(Record, Idx)); + E->setArgument(Reader.GetTypeSourceInfo(Record, Idx)); } E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -456,7 +456,7 @@ unsigned PCHStmtReader::VisitCallExpr(CallExpr *E) { unsigned PCHStmtReader::VisitMemberExpr(MemberExpr *E) { VisitExpr(E); E->setBase(cast<Expr>(StmtStack.back())); - E->setMemberDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); + E->setMemberDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++]))); E->setMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setArrow(Record[Idx++]); return 1; diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index e79f9c9dac19..681c1ff32cb0 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -166,6 +166,14 @@ void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { Code = pch::TYPE_FUNCTION_PROTO; } +#if 0 +// For when we want it.... +void PCHTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_UNRESOLVED_USING; +} +#endif + void PCHTypeWriter::VisitTypedefType(const TypedefType *T) { Writer.AddDeclRef(T->getDecl(), Record); Code = pch::TYPE_TYPEDEF; @@ -337,6 +345,9 @@ void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } +void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } @@ -770,6 +781,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.getStackProtectorMode()); Record.push_back(LangOpts.InstantiationDepth); Record.push_back(LangOpts.OpenCL); + Record.push_back(LangOpts.CatchUndefined); Record.push_back(LangOpts.ElideConstructors); Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record); } @@ -2129,7 +2141,7 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, AddStmt(Arg.getLocInfo().getAsExpr()); break; case TemplateArgument::Type: - AddDeclaratorInfo(Arg.getLocInfo().getAsDeclaratorInfo(), Record); + AddTypeSourceInfo(Arg.getLocInfo().getAsTypeSourceInfo(), Record); break; case TemplateArgument::Template: Record.push_back( @@ -2145,15 +2157,15 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, } } -void PCHWriter::AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record) { - if (DInfo == 0) { +void PCHWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record) { + if (TInfo == 0) { AddTypeRef(QualType(), Record); return; } - AddTypeRef(DInfo->getType(), Record); + AddTypeRef(TInfo->getType(), Record); TypeLocWriter TLW(*this, Record); - for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) TLW.Visit(TL); } diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index c7bfee2c8bcd..049cdb03ea3b 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -14,9 +14,9 @@ #include "clang/Frontend/PCHWriter.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" +#include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamWriter.h" -#include <cstdio> - +#include "llvm/Support/ErrorHandling.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -106,7 +106,7 @@ void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) { void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) { VisitTypeDecl(D); - Writer.AddDeclaratorInfo(D->getTypeDeclaratorInfo(), Record); + Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); Code = pch::DECL_TYPEDEF; } @@ -123,6 +123,7 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) { void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) { VisitTagDecl(D); Writer.AddTypeRef(D->getIntegerType(), Record); + Writer.AddTypeRef(D->getPromotionType(), Record); // FIXME: C++ InstantiatedFrom Code = pch::DECL_ENUM; } @@ -151,7 +152,7 @@ void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { VisitValueDecl(D); - Writer.AddDeclaratorInfo(D->getDeclaratorInfo(), Record); + Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); } void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { @@ -370,7 +371,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here // we dynamically check for the properties that we optimize for, but don't // know are true of all PARM_VAR_DECLs. - if (!D->getDeclaratorInfo() && + if (!D->getTypeSourceInfo() && !D->hasAttrs() && !D->isImplicit() && !D->isUsed() && @@ -568,12 +569,9 @@ void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) { W.Visit(D); if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); - if (!W.Code) { - fprintf(stderr, "Cannot serialize declaration of kind %s\n", - D->getDeclKindName()); - assert(false && "Unhandled declaration kind while generating PCH"); - exit(-1); - } + if (!W.Code) + llvm::llvm_report_error(llvm::StringRef("unexpected declaration kind '") + + D->getDeclKindName() + "'"); Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); // If the declaration had any attributes, write them now. diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 27b83ed6cbb2..22f7ad66d9d1 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -388,7 +388,7 @@ void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { VisitExpr(E); Record.push_back(E->isSizeOf()); if (E->isArgumentType()) - Writer.AddDeclaratorInfo(E->getArgumentTypeInfo(), Record); + Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record); else { Record.push_back(0); Writer.WriteSubStmt(E->getArgumentExpr()); diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index 80ee2c2e8eba..92cafe6d1cbe 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -30,6 +30,40 @@ namespace clang { } namespace { +struct CompareDiagnostics { + // Compare if 'X' is "<" than 'Y'. + bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { + // First compare by location + const FullSourceLoc &XLoc = X->getLocation().asLocation(); + const FullSourceLoc &YLoc = Y->getLocation().asLocation(); + if (XLoc < YLoc) + return true; + if (XLoc != YLoc) + return false; + + // Next, compare by bug type. + llvm::StringRef XBugType = X->getBugType(); + llvm::StringRef YBugType = Y->getBugType(); + if (XBugType < YBugType) + return true; + if (XBugType != YBugType) + return false; + + // Next, compare by bug description. + llvm::StringRef XDesc = X->getDescription(); + llvm::StringRef YDesc = Y->getDescription(); + if (XDesc < YDesc) + return true; + if (XDesc != YDesc) + return false; + + // FIXME: Further refine by comparing PathDiagnosticPieces? + return false; + } +}; +} + +namespace { class PlistDiagnostics : public PathDiagnosticClient { std::vector<const PathDiagnostic*> BatchedDiags; const std::string OutputFile; @@ -314,6 +348,11 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> return; flushed = true; + + // Sort the diagnostics so that they are always emitted in a deterministic + // order. + if (!BatchedDiags.empty()) + std::sort(BatchedDiags.begin(), BatchedDiags.end(), CompareDiagnostics()); // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 37424057809c..d9708d8bced4 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -36,22 +36,23 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, if (MI.isFunctionLike()) { OS << '('; - if (MI.arg_empty()) - ; - else if (MI.getNumArgs() == 1) - OS << (*MI.arg_begin())->getName(); - else { + if (!MI.arg_empty()) { MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end(); - OS << (*AI++)->getName(); - while (AI != E) - OS << ',' << (*AI++)->getName(); - } - - if (MI.isVariadic()) { - if (!MI.arg_empty()) + for (; AI+1 != E; ++AI) { + OS << (*AI)->getName(); OS << ','; - OS << "..."; + } + + // Last argument. + if ((*AI)->getName() == "__VA_ARGS__") + OS << "..."; + else + OS << (*AI)->getName(); } + + if (MI.isGNUVarargs()) + OS << "..."; // #define foo(x...) + OS << ')'; } @@ -94,6 +95,7 @@ private: bool Initialized; bool DisableLineMarkers; bool DumpDefines; + bool UseLineDirective; public: PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os, bool lineMarkers, bool defines) @@ -105,6 +107,9 @@ public: EmittedMacroOnThisLine = false; FileType = SrcMgr::C_User; Initialized = false; + + // If we're in microsoft mode, use normal #line instead of line markers. + UseLineDirective = PP.getLangOptions().Microsoft; } void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; } @@ -141,17 +146,24 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo, EmittedMacroOnThisLine = false; } - OS << '#' << ' ' << LineNo << ' ' << '"'; - OS.write(&CurFilename[0], CurFilename.size()); - OS << '"'; - - if (ExtraLen) - OS.write(Extra, ExtraLen); - - if (FileType == SrcMgr::C_System) - OS.write(" 3", 2); - else if (FileType == SrcMgr::C_ExternCSystem) - OS.write(" 3 4", 4); + // Emit #line directives or GNU line markers depending on what mode we're in. + if (UseLineDirective) { + OS << "#line" << ' ' << LineNo << ' ' << '"'; + OS.write(&CurFilename[0], CurFilename.size()); + OS << '"'; + } else { + OS << '#' << ' ' << LineNo << ' ' << '"'; + OS.write(&CurFilename[0], CurFilename.size()); + OS << '"'; + + if (ExtraLen) + OS.write(Extra, ExtraLen); + + if (FileType == SrcMgr::C_System) + OS.write(" 3", 2); + else if (FileType == SrcMgr::C_ExternCSystem) + OS.write(" 3 4", 4); + } OS << '\n'; } diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 710fa55b69bf..df85c13cea78 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -255,7 +255,10 @@ namespace { Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); - void WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S); + void WarnAboutReturnGotoStmts(Stmt *S); + void HasReturnStmts(Stmt *S, bool &hasReturns); + void RewriteTryReturnStmts(Stmt *S); + void RewriteSyncReturnStmts(Stmt *S, std::string buf); Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S); @@ -328,11 +331,16 @@ namespace { const char *funcName, std::string Tag); std::string SynthesizeBlockFunc(BlockExpr *CE, int i, const char *funcName, std::string Tag); - std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - bool hasCopyDisposeHelpers); + std::string SynthesizeBlockImpl(BlockExpr *CE, + std::string Tag, std::string Desc); + std::string SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, + int i, const char *funcName, + unsigned hasCopy); Stmt *SynthesizeBlockCall(CallExpr *Exp); void SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName); + void RewriteRecordBody(RecordDecl *RD); void CollectBlockDeclRefInfo(BlockExpr *Exp); void GetBlockCallExprs(Stmt *S); @@ -547,14 +555,21 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "struct __block_impl {\n"; Preamble += " void *isa;\n"; Preamble += " int Flags;\n"; - Preamble += " int Size;\n"; + Preamble += " int Reserved;\n"; Preamble += " void *FuncPtr;\n"; Preamble += "};\n"; Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; - Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_dispose(const void *, const int);\n"; - Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteStackBlock[32];\n"; + Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; + Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; + Preamble += "#else\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; + Preamble += "#endif\n"; Preamble += "#endif\n"; if (LangOpts.Microsoft) { Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; @@ -1325,7 +1340,12 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, // type elem; NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl()); QualType ElementType = cast<ValueDecl>(D)->getType(); - elementTypeAsString = ElementType.getAsString(); + if (ElementType->isObjCQualifiedIdType() || + ElementType->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = ElementType.getAsString(); buf += elementTypeAsString; buf += " "; elementName = D->getNameAsCString(); @@ -1335,8 +1355,13 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, else { DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement()); elementName = DR->getDecl()->getNameAsCString(); - elementTypeAsString - = cast<ValueDecl>(DR->getDecl())->getType().getAsString(); + ValueDecl *VD = cast<ValueDecl>(DR->getDecl()); + if (VD->getType()->isObjCQualifiedIdType() || + VD->getType()->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = VD->getType().getAsString(); } // struct __objcFastEnumerationState enumState = { 0 }; @@ -1502,7 +1527,9 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { buf += "}\n"; buf += "{ /* implicit finally clause */\n"; buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; - buf += " objc_sync_exit("; + + std::string syncBuf; + syncBuf += " objc_sync_exit("; Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), CastExpr::CK_Unknown, S->getSynchExpr(), @@ -1513,31 +1540,102 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { llvm::raw_string_ostream syncExprBuf(syncExprBufS); syncExpr->printPretty(syncExprBuf, *Context, 0, PrintingPolicy(LangOpts)); - buf += syncExprBuf.str(); - buf += ");\n"; - buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; + syncBuf += syncExprBuf.str(); + syncBuf += ");"; + + buf += syncBuf; + buf += "\n if (_rethrow) objc_exception_throw(_rethrow);\n"; buf += "}\n"; buf += "}"; ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size()); + + bool hasReturns = false; + HasReturnStmts(S->getSynchBody(), hasReturns); + if (hasReturns) + RewriteSyncReturnStmts(S->getSynchBody(), syncBuf); + return 0; } -void RewriteObjC::WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S) { +void RewriteObjC::WarnAboutReturnGotoStmts(Stmt *S) +{ // Perform a bottom up traversal of all children. for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; ++CI) if (*CI) - WarnAboutReturnGotoContinueOrBreakStmts(*CI); + WarnAboutReturnGotoStmts(*CI); - if (isa<ReturnStmt>(S) || isa<ContinueStmt>(S) || - isa<BreakStmt>(S) || isa<GotoStmt>(S)) { + if (isa<ReturnStmt>(S) || isa<GotoStmt>(S)) { Diags.Report(Context->getFullLoc(S->getLocStart()), TryFinallyContainsReturnDiag); } return; } +void RewriteObjC::HasReturnStmts(Stmt *S, bool &hasReturns) +{ + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) + HasReturnStmts(*CI, hasReturns); + + if (isa<ReturnStmt>(S)) + hasReturns = true; + return; +} + +void RewriteObjC::RewriteTryReturnStmts(Stmt *S) { + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + RewriteTryReturnStmts(*CI); + } + if (isa<ReturnStmt>(S)) { + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'"); + SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + + std::string buf; + buf = "{ objc_exception_try_exit(&_stack); return"; + + ReplaceText(startLoc, 6, buf.c_str(), buf.size()); + InsertText(onePastSemiLoc, "}", 1); + } + return; +} + +void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) { + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + RewriteSyncReturnStmts(*CI, syncExitBuf); + } + if (isa<ReturnStmt>(S)) { + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'"); + SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + + std::string buf; + buf = "{ objc_exception_try_exit(&_stack);"; + buf += syncExitBuf; + buf += " return"; + + ReplaceText(startLoc, 6, buf.c_str(), buf.size()); + InsertText(onePastSemiLoc, "}", 1); + } + return; +} + Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { // Get the start location and compute the semi location. SourceLocation startLoc = S->getLocStart(); @@ -1689,13 +1787,21 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { lastCurlyLoc = body->getLocEnd(); // Now check for any return/continue/go statements within the @try. - WarnAboutReturnGotoContinueOrBreakStmts(S->getTryBody()); + WarnAboutReturnGotoStmts(S->getTryBody()); } else { /* no finally clause - make sure we synthesize an implicit one */ buf = "{ /* implicit finally clause */\n"; buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; buf += "}"; ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size()); + + // Now check for any return/continue/go statements within the @try. + // The implicit finally clause won't called if the @try contains any + // jump statements. + bool hasReturns = false; + HasReturnStmts(S->getTryBody(), hasReturns); + if (hasReturns) + RewriteTryReturnStmts(S->getTryBody()); } // Now emit the final closing curly brace... lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1); @@ -1878,6 +1984,10 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { return; Type = proto->getResultType(); } + else if (FieldDecl *FD = dyn_cast<FieldDecl>(Dcl)) { + Loc = FD->getLocation(); + Type = FD->getType(); + } else return; @@ -2134,8 +2244,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { PrintingPolicy(LangOpts)); Preamble += prettyBuf.str(); Preamble += ","; - // The minus 2 removes the begin/end double quotes. - Preamble += utostr(prettyBuf.str().size()-2) + "};\n"; + Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get(S.c_str()), strType, 0, @@ -2569,7 +2678,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // Build sizeof(returnType) SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, - Context->getTrivialDeclaratorInfo(returnType), + Context->getTrivialTypeSourceInfo(returnType), Context->getSizeType(), SourceLocation(), SourceLocation()); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) @@ -2609,12 +2718,12 @@ Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { // typedef struct objc_object Protocol; QualType RewriteObjC::getProtocolType() { if (!ProtocolTypeDecl) { - DeclaratorInfo *DInfo - = Context->getTrivialDeclaratorInfo(Context->getObjCIdType()); + TypeSourceInfo *TInfo + = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get("Protocol"), - DInfo); + TInfo); } return Context->getTypeDeclType(ProtocolTypeDecl); } @@ -2737,7 +2846,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, ReplaceText(LocStart, endHeader-startBuf, Result.c_str(), Result.size()); } else { // rewrite the original header *without* disturbing the '{' - ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size()); + ReplaceText(LocStart, cursor-startBuf, Result.c_str(), Result.size()); } if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { Result = "\n struct "; @@ -3689,20 +3798,18 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, return S; } -std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - bool hasCopyDisposeHelpers) { +std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, + std::string Desc) { std::string S = "\nstruct " + Tag; std::string Constructor = " " + Tag; S += " {\n struct __block_impl impl;\n"; + S += " struct " + Desc; + S += "* Desc;\n"; - if (hasCopyDisposeHelpers) - S += " void *copy;\n void *dispose;\n"; - - Constructor += "(void *fp"; - - if (hasCopyDisposeHelpers) - Constructor += ", void *copyHelp, void *disposeHelp"; + Constructor += "(void *fp, "; // Invoke function pointer. + Constructor += "struct " + Desc; // Descriptor pointer. + Constructor += " *desc"; if (BlockDeclRefs.size()) { // Output all "by copy" declarations. @@ -3765,11 +3872,9 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; else Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Size = sizeof("; - Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - if (hasCopyDisposeHelpers) - Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n"; + Constructor += " Desc = desc;\n"; // Initialize all "by copy" arguments. for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), @@ -3800,10 +3905,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; else Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Size = sizeof("; - Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - if (hasCopyDisposeHelpers) - Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + Constructor += " Desc = desc;\n"; } Constructor += " "; Constructor += "}\n"; @@ -3812,6 +3915,29 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, return S; } +std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, int i, + const char *FunName, + unsigned hasCopy) { + std::string S = "\nstatic struct " + DescTag; + + S += " {\n unsigned long reserved;\n"; + S += " unsigned long Block_size;\n"; + if (hasCopy) { + S += " void *copy;\n void *dispose;\n"; + } + S += "} "; + + S += DescTag + "_DATA = { 0, sizeof(struct "; + S += ImplTag + ")"; + if (hasCopy) { + S += ", __" + std::string(FunName) + "_block_copy_" + utostr(i); + S += ", __" + std::string(FunName) + "_block_dispose_" + utostr(i); + } + S += "};\n"; + return S; +} + void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName) { // Insert closures that were part of the function. @@ -3819,21 +3945,24 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, CollectBlockDeclRefInfo(Blocks[i]); - std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); + std::string ImplTag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); + std::string DescTag = "__" + std::string(FunName) + "_block_desc_" + utostr(i); - std::string CI = SynthesizeBlockImpl(Blocks[i], Tag, - ImportedBlockDecls.size() > 0); + std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); InsertText(FunLocStart, CI.c_str(), CI.size()); - std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag); + std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); InsertText(FunLocStart, CF.c_str(), CF.size()); if (ImportedBlockDecls.size()) { - std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag); + std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); InsertText(FunLocStart, HF.c_str(), HF.size()); } + std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, + ImportedBlockDecls.size() > 0); + InsertText(FunLocStart, BD.c_str(), BD.size()); BlockDeclRefs.clear(); BlockByRefDecls.clear(); @@ -4243,25 +4372,21 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { SourceLocation()); InitExprs.push_back(castExpr); - if (ImportedBlockDecls.size()) { - std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber; - FD = SynthBlockInitFunctionDecl(Buf.c_str()); - Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg, - Context->VoidPtrTy, SourceLocation(), - SourceLocation()); - InitExprs.push_back(castExpr); - - Buf = "__" + FuncName + "_block_dispose_" + BlockNumber; - FD = SynthBlockInitFunctionDecl(Buf.c_str()); - Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg, - Context->VoidPtrTy, SourceLocation(), - SourceLocation()); - InitExprs.push_back(castExpr); - } + // Initialize the block descriptor. + std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; + + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + &Context->Idents.get(DescData.c_str()), + Context->VoidPtrTy, 0, + VarDecl::Static); + UnaryOperator *DescRefExpr = new (Context) UnaryOperator( + new (Context) DeclRefExpr(NewVD, + Context->VoidPtrTy, SourceLocation()), + UnaryOperator::AddrOf, + Context->getPointerType(Context->VoidPtrTy), + SourceLocation()); + InitExprs.push_back(DescRefExpr); + // Add initializers for any closure decl refs. if (BlockDeclRefs.size()) { Expr *Exp; @@ -4297,6 +4422,17 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { InitExprs.push_back(Exp); } } + if (ImportedBlockDecls.size()) { // generate "1<<25" to indicate we have helper functions. + unsigned IntSize = + static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); + BinaryOperator *Exp = new (Context) BinaryOperator( + new (Context) IntegerLiteral(llvm::APInt(IntSize, 1), + Context->IntTy,SourceLocation()), + new (Context) IntegerLiteral(llvm::APInt(IntSize, 25), + Context->IntTy, SourceLocation()), + BinaryOperator::Shl, Context->IntTy, SourceLocation()); + InitExprs.push_back(Exp); + } NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), FType, SourceLocation()); NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf, @@ -4486,7 +4622,14 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { // FIXME: What we're doing here is modifying the type-specifier that // precedes the first Decl. In the future the DeclGroup should have // a separate type-specifier that we can rewrite. - RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); + // NOTE: We need to avoid rewriting the DeclStmt if it is within + // the context of an ObjCForCollectionStmt. For example: + // NSArray *someArray; + // for (id <FooProtocol> index in someArray) ; + // This is because RewriteObjCForCollectionStmt() does textual rewriting + // and it depends on the original text locations/positions. + if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) + RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); // Blocks rewrite rules. for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); @@ -4552,6 +4695,18 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { return S; } +void RewriteObjC::RewriteRecordBody(RecordDecl *RD) { + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i) { + FieldDecl *FD = *i; + if (isTopLevelBlockPointerType(FD->getType())) + RewriteBlockPointerDecl(FD); + if (FD->getType()->isObjCQualifiedIdType() || + FD->getType()->isObjCQualifiedInterfaceType()) + RewriteObjCQualifiedInterfaceTypes(FD); + } +} + /// HandleDeclInMainFile - This is called for each top-level decl defined in the /// main file of the input. void RewriteObjC::HandleDeclInMainFile(Decl *D) { @@ -4618,6 +4773,10 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { RewriteCastExpr(CE); } } + } else if (VD->getType()->isRecordType()) { + RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl(); + if (RD->isDefinition()) + RewriteRecordBody(RD); } if (VD->getInit()) { GlobalVarDecl = VD; @@ -4645,17 +4804,16 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { RewriteBlockPointerDecl(TD); else if (TD->getUnderlyingType()->isFunctionPointerType()) CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); + else if (TD->getUnderlyingType()->isRecordType()) { + RecordDecl *RD = TD->getUnderlyingType()->getAs<RecordType>()->getDecl(); + if (RD->isDefinition()) + RewriteRecordBody(RD); + } return; } if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) { - if (RD->isDefinition()) { - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - if (isTopLevelBlockPointerType(FD->getType())) - RewriteBlockPointerDecl(FD); - } - } + if (RD->isDefinition()) + RewriteRecordBody(RD); return; } // Nothing yet. diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 6ab0e1605276..61f8a70fffff 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -279,13 +279,14 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, assert(!Loc.isInvalid() && "must have a valid source location here"); // If this is a macro ID, first emit information about where this was - // instantiated (recursively) then emit information about where. the token was + // instantiated (recursively) then emit information about where the token was // spelled from. if (!Loc.isFileID()) { SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first; // FIXME: Map ranges? EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns); + // Map the location. Loc = SM.getImmediateSpellingLoc(Loc); // Map the ranges. @@ -295,15 +296,22 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E); Ranges[i] = SourceRange(S, E); } + + // Get the pretty name, according to #line directives etc. + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + + // If this diagnostic is not in the main file, print out the "included from" + // lines. + if (LastWarningLoc != PLoc.getIncludeLoc()) { + LastWarningLoc = PLoc.getIncludeLoc(); + PrintIncludeStack(LastWarningLoc, SM); + } if (DiagOpts->ShowLocation) { - std::pair<FileID, unsigned> IInfo = SM.getDecomposedInstantiationLoc(Loc); - // Emit the file/line/column that this expansion came from. - OS << SM.getBuffer(IInfo.first)->getBufferIdentifier() << ':' - << SM.getLineNumber(IInfo.first, IInfo.second) << ':'; + OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'; if (DiagOpts->ShowColumn) - OS << SM.getColumnNumber(IInfo.first, IInfo.second) << ':'; + OS << PLoc.getColumn() << ':'; OS << ' '; } OS << "note: instantiated from:\n"; @@ -489,12 +497,17 @@ static inline char findMatchingPunctuation(char c) { /// /// \returns the index pointing one character past the end of the /// word. -unsigned findEndOfWord(unsigned Start, - const llvm::SmallVectorImpl<char> &Str, - unsigned Length, unsigned Column, - unsigned Columns) { +static unsigned findEndOfWord(unsigned Start, + const llvm::SmallVectorImpl<char> &Str, + unsigned Length, unsigned Column, + unsigned Columns) { + assert(Start < Str.size() && "Invalid start position!"); unsigned End = Start + 1; + // If we are already at the end of the string, take that as the word. + if (End == Str.size()) + return End; + // Determine if the start of the string is actually opening // punctuation, e.g., a quote or parentheses. char EndPunct = findMatchingPunctuation(Str[Start]); @@ -645,11 +658,17 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, if (DiagOpts->ShowLocation) { if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); - OS << PLoc.getFilename() << ':' << LineNo << ':'; - if (DiagOpts->ShowColumn) - if (unsigned ColNo = PLoc.getColumn()) - OS << ColNo << ':'; - + + // Emit a Visual Studio compatible line number syntax. + if (LangOpts && LangOpts->Microsoft) { + OS << PLoc.getFilename() << '(' << LineNo << ')'; + OS << " : "; + } else { + OS << PLoc.getFilename() << ':' << LineNo << ':'; + if (DiagOpts->ShowColumn) + if (unsigned ColNo = PLoc.getColumn()) + OS << ColNo << ':'; + } if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { FileID CaretFileID = SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); |