CompilerInstance.cpp revision e082af17d4b425a49f7f8bccc2a99810f0072828
1//===--- CompilerInstance.cpp ---------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/Frontend/CompilerInstance.h"
11#include "clang/Sema/Sema.h"
12#include "clang/AST/ASTConsumer.h"
13#include "clang/AST/ASTContext.h"
14#include "clang/Basic/Diagnostic.h"
15#include "clang/Basic/FileManager.h"
16#include "clang/Basic/SourceManager.h"
17#include "clang/Basic/TargetInfo.h"
18#include "clang/Basic/Version.h"
19#include "clang/Lex/HeaderSearch.h"
20#include "clang/Lex/Preprocessor.h"
21#include "clang/Lex/PTHManager.h"
22#include "clang/Frontend/ChainedDiagnosticClient.h"
23#include "clang/Frontend/FrontendAction.h"
24#include "clang/Frontend/FrontendDiagnostic.h"
25#include "clang/Frontend/LogDiagnosticPrinter.h"
26#include "clang/Frontend/TextDiagnosticPrinter.h"
27#include "clang/Frontend/VerifyDiagnosticsClient.h"
28#include "clang/Frontend/Utils.h"
29#include "clang/Serialization/ASTReader.h"
30#include "clang/Sema/CodeCompleteConsumer.h"
31#include "llvm/Support/FileSystem.h"
32#include "llvm/Support/MemoryBuffer.h"
33#include "llvm/Support/raw_ostream.h"
34#include "llvm/ADT/Statistic.h"
35#include "llvm/Support/Timer.h"
36#include "llvm/Support/Host.h"
37#include "llvm/Support/Path.h"
38#include "llvm/Support/Program.h"
39#include "llvm/Support/Signals.h"
40#include "llvm/Support/system_error.h"
41#include "llvm/Config/config.h"
42using namespace clang;
43
44CompilerInstance::CompilerInstance()
45  : Invocation(new CompilerInvocation()), ModuleManager(0) {
46}
47
48CompilerInstance::~CompilerInstance() {
49}
50
51void CompilerInstance::setInvocation(CompilerInvocation *Value) {
52  Invocation = Value;
53}
54
55void CompilerInstance::setDiagnostics(Diagnostic *Value) {
56  Diagnostics = Value;
57}
58
59void CompilerInstance::setTarget(TargetInfo *Value) {
60  Target = Value;
61}
62
63void CompilerInstance::setFileManager(FileManager *Value) {
64  FileMgr = Value;
65}
66
67void CompilerInstance::setSourceManager(SourceManager *Value) {
68  SourceMgr = Value;
69}
70
71void CompilerInstance::setPreprocessor(Preprocessor *Value) { PP = Value; }
72
73void CompilerInstance::setASTContext(ASTContext *Value) { Context = Value; }
74
75void CompilerInstance::setSema(Sema *S) {
76  TheSema.reset(S);
77}
78
79void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
80  Consumer.reset(Value);
81}
82
83void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
84  CompletionConsumer.reset(Value);
85}
86
87// Diagnostics
88static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
89                              unsigned argc, const char* const *argv,
90                              Diagnostic &Diags) {
91  std::string ErrorInfo;
92  llvm::OwningPtr<raw_ostream> OS(
93    new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo));
94  if (!ErrorInfo.empty()) {
95    Diags.Report(diag::err_fe_unable_to_open_logfile)
96                 << DiagOpts.DumpBuildInformation << ErrorInfo;
97    return;
98  }
99
100  (*OS) << "clang -cc1 command line arguments: ";
101  for (unsigned i = 0; i != argc; ++i)
102    (*OS) << argv[i] << ' ';
103  (*OS) << '\n';
104
105  // Chain in a diagnostic client which will log the diagnostics.
106  DiagnosticClient *Logger =
107    new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true);
108  Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger));
109}
110
111static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts,
112                               const CodeGenOptions *CodeGenOpts,
113                               Diagnostic &Diags) {
114  std::string ErrorInfo;
115  bool OwnsStream = false;
116  raw_ostream *OS = &llvm::errs();
117  if (DiagOpts.DiagnosticLogFile != "-") {
118    // Create the output stream.
119    llvm::raw_fd_ostream *FileOS(
120      new llvm::raw_fd_ostream(DiagOpts.DiagnosticLogFile.c_str(),
121                               ErrorInfo, llvm::raw_fd_ostream::F_Append));
122    if (!ErrorInfo.empty()) {
123      Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
124        << DiagOpts.DumpBuildInformation << ErrorInfo;
125    } else {
126      FileOS->SetUnbuffered();
127      FileOS->SetUseAtomicWrites(true);
128      OS = FileOS;
129      OwnsStream = true;
130    }
131  }
132
133  // Chain in the diagnostic client which will log the diagnostics.
134  LogDiagnosticPrinter *Logger = new LogDiagnosticPrinter(*OS, DiagOpts,
135                                                          OwnsStream);
136  if (CodeGenOpts)
137    Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags);
138  Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger));
139}
140
141void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
142                                         DiagnosticClient *Client) {
143  Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client,
144                                  &getCodeGenOpts());
145}
146
147llvm::IntrusiveRefCntPtr<Diagnostic>
148CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
149                                    int Argc, const char* const *Argv,
150                                    DiagnosticClient *Client,
151                                    const CodeGenOptions *CodeGenOpts) {
152  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
153  llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID));
154
155  // Create the diagnostic client for reporting errors or for
156  // implementing -verify.
157  if (Client)
158    Diags->setClient(Client);
159  else
160    Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
161
162  // Chain in -verify checker, if requested.
163  if (Opts.VerifyDiagnostics)
164    Diags->setClient(new VerifyDiagnosticsClient(*Diags, Diags->takeClient()));
165
166  // Chain in -diagnostic-log-file dumper, if requested.
167  if (!Opts.DiagnosticLogFile.empty())
168    SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
169
170  if (!Opts.DumpBuildInformation.empty())
171    SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
172
173  // Configure our handling of diagnostics.
174  ProcessWarningOptions(*Diags, Opts);
175
176  return Diags;
177}
178
179// File Manager
180
181void CompilerInstance::createFileManager() {
182  FileMgr = new FileManager(getFileSystemOpts());
183}
184
185// Source Manager
186
187void CompilerInstance::createSourceManager(FileManager &FileMgr) {
188  SourceMgr = new SourceManager(getDiagnostics(), FileMgr);
189}
190
191// Preprocessor
192
193void CompilerInstance::createPreprocessor() {
194  const PreprocessorOptions &PPOpts = getPreprocessorOpts();
195
196  // Create a PTH manager if we are using some form of a token cache.
197  PTHManager *PTHMgr = 0;
198  if (!PPOpts.TokenCache.empty())
199    PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics());
200
201  // Create the Preprocessor.
202  HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager());
203  PP = new Preprocessor(getDiagnostics(), getLangOpts(), getTarget(),
204                        getSourceManager(), *HeaderInfo, *this, PTHMgr,
205                        /*OwnsHeaderSearch=*/true);
206
207  // Note that this is different then passing PTHMgr to Preprocessor's ctor.
208  // That argument is used as the IdentifierInfoLookup argument to
209  // IdentifierTable's ctor.
210  if (PTHMgr) {
211    PTHMgr->setPreprocessor(&*PP);
212    PP->setPTHManager(PTHMgr);
213  }
214
215  if (PPOpts.DetailedRecord)
216    PP->createPreprocessingRecord(
217                                  PPOpts.DetailedRecordIncludesNestedMacroExpansions);
218
219  InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts());
220
221  // Handle generating dependencies, if requested.
222  const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
223  if (!DepOpts.OutputFile.empty())
224    AttachDependencyFileGen(*PP, DepOpts);
225
226  // Handle generating header include information, if requested.
227  if (DepOpts.ShowHeaderIncludes)
228    AttachHeaderIncludeGen(*PP);
229  if (!DepOpts.HeaderIncludeOutputFile.empty()) {
230    StringRef OutputPath = DepOpts.HeaderIncludeOutputFile;
231    if (OutputPath == "-")
232      OutputPath = "";
233    AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath,
234                           /*ShowDepth=*/false);
235  }
236}
237
238// ASTContext
239
240void CompilerInstance::createASTContext() {
241  Preprocessor &PP = getPreprocessor();
242  Context = new ASTContext(getLangOpts(), PP.getSourceManager(),
243                           getTarget(), PP.getIdentifierTable(),
244                           PP.getSelectorTable(), PP.getBuiltinInfo(),
245                           /*size_reserve=*/ 0);
246}
247
248// ExternalASTSource
249
250void CompilerInstance::createPCHExternalASTSource(StringRef Path,
251                                                  bool DisablePCHValidation,
252                                                  bool DisableStatCache,
253                                                 void *DeserializationListener){
254  llvm::OwningPtr<ExternalASTSource> Source;
255  bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
256  Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
257                                          DisablePCHValidation,
258                                          DisableStatCache,
259                                          getPreprocessor(), getASTContext(),
260                                          DeserializationListener,
261                                          Preamble));
262  ModuleManager = static_cast<ASTReader*>(Source.get());
263  getASTContext().setExternalSource(Source);
264}
265
266ExternalASTSource *
267CompilerInstance::createPCHExternalASTSource(StringRef Path,
268                                             const std::string &Sysroot,
269                                             bool DisablePCHValidation,
270                                             bool DisableStatCache,
271                                             Preprocessor &PP,
272                                             ASTContext &Context,
273                                             void *DeserializationListener,
274                                             bool Preamble) {
275  llvm::OwningPtr<ASTReader> Reader;
276  Reader.reset(new ASTReader(PP, &Context,
277                             Sysroot.empty() ? "" : Sysroot.c_str(),
278                             DisablePCHValidation, DisableStatCache));
279
280  Reader->setDeserializationListener(
281            static_cast<ASTDeserializationListener *>(DeserializationListener));
282  switch (Reader->ReadAST(Path,
283                          Preamble ? serialization::MK_Preamble
284                                   : serialization::MK_PCH)) {
285  case ASTReader::Success:
286    // Set the predefines buffer as suggested by the PCH reader. Typically, the
287    // predefines buffer will be empty.
288    PP.setPredefines(Reader->getSuggestedPredefines());
289    return Reader.take();
290
291  case ASTReader::Failure:
292    // Unrecoverable failure: don't even try to process the input file.
293    break;
294
295  case ASTReader::IgnorePCH:
296    // No suitable PCH file could be found. Return an error.
297    break;
298  }
299
300  return 0;
301}
302
303// Code Completion
304
305static bool EnableCodeCompletion(Preprocessor &PP,
306                                 const std::string &Filename,
307                                 unsigned Line,
308                                 unsigned Column) {
309  // Tell the source manager to chop off the given file at a specific
310  // line and column.
311  const FileEntry *Entry = PP.getFileManager().getFile(Filename);
312  if (!Entry) {
313    PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file)
314      << Filename;
315    return true;
316  }
317
318  // Truncate the named file at the given line/column.
319  PP.SetCodeCompletionPoint(Entry, Line, Column);
320  return false;
321}
322
323void CompilerInstance::createCodeCompletionConsumer() {
324  const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt;
325  if (!CompletionConsumer) {
326    CompletionConsumer.reset(
327      createCodeCompletionConsumer(getPreprocessor(),
328                                   Loc.FileName, Loc.Line, Loc.Column,
329                                   getFrontendOpts().ShowMacrosInCodeCompletion,
330                             getFrontendOpts().ShowCodePatternsInCodeCompletion,
331                           getFrontendOpts().ShowGlobalSymbolsInCodeCompletion,
332                                   llvm::outs()));
333    if (!CompletionConsumer)
334      return;
335  } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName,
336                                  Loc.Line, Loc.Column)) {
337    CompletionConsumer.reset();
338    return;
339  }
340
341  if (CompletionConsumer->isOutputBinary() &&
342      llvm::sys::Program::ChangeStdoutToBinary()) {
343    getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary);
344    CompletionConsumer.reset();
345  }
346}
347
348void CompilerInstance::createFrontendTimer() {
349  FrontendTimer.reset(new llvm::Timer("Clang front-end timer"));
350}
351
352CodeCompleteConsumer *
353CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
354                                               const std::string &Filename,
355                                               unsigned Line,
356                                               unsigned Column,
357                                               bool ShowMacros,
358                                               bool ShowCodePatterns,
359                                               bool ShowGlobals,
360                                               raw_ostream &OS) {
361  if (EnableCodeCompletion(PP, Filename, Line, Column))
362    return 0;
363
364  // Set up the creation routine for code-completion.
365  return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns,
366                                          ShowGlobals, OS);
367}
368
369void CompilerInstance::createSema(TranslationUnitKind TUKind,
370                                  CodeCompleteConsumer *CompletionConsumer) {
371  TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(),
372                         TUKind, CompletionConsumer));
373}
374
375// Output Files
376
377void CompilerInstance::addOutputFile(const OutputFile &OutFile) {
378  assert(OutFile.OS && "Attempt to add empty stream to output list!");
379  OutputFiles.push_back(OutFile);
380}
381
382void CompilerInstance::clearOutputFiles(bool EraseFiles) {
383  for (std::list<OutputFile>::iterator
384         it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
385    delete it->OS;
386    if (!it->TempFilename.empty()) {
387      if (EraseFiles) {
388        bool existed;
389        llvm::sys::fs::remove(it->TempFilename, existed);
390      } else {
391        llvm::SmallString<128> NewOutFile(it->Filename);
392
393        // If '-working-directory' was passed, the output filename should be
394        // relative to that.
395        FileMgr->FixupRelativePath(NewOutFile);
396        if (llvm::error_code ec = llvm::sys::fs::rename(it->TempFilename,
397                                                        NewOutFile.str())) {
398          getDiagnostics().Report(diag::err_fe_unable_to_rename_temp)
399            << it->TempFilename << it->Filename << ec.message();
400
401          bool existed;
402          llvm::sys::fs::remove(it->TempFilename, existed);
403        }
404      }
405    } else if (!it->Filename.empty() && EraseFiles)
406      llvm::sys::Path(it->Filename).eraseFromDisk();
407
408  }
409  OutputFiles.clear();
410}
411
412llvm::raw_fd_ostream *
413CompilerInstance::createDefaultOutputFile(bool Binary,
414                                          StringRef InFile,
415                                          StringRef Extension) {
416  return createOutputFile(getFrontendOpts().OutputFile, Binary,
417                          /*RemoveFileOnSignal=*/true, InFile, Extension);
418}
419
420llvm::raw_fd_ostream *
421CompilerInstance::createOutputFile(StringRef OutputPath,
422                                   bool Binary, bool RemoveFileOnSignal,
423                                   StringRef InFile,
424                                   StringRef Extension,
425                                   bool UseTemporary) {
426  std::string Error, OutputPathName, TempPathName;
427  llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
428                                              RemoveFileOnSignal,
429                                              InFile, Extension,
430                                              UseTemporary,
431                                              &OutputPathName,
432                                              &TempPathName);
433  if (!OS) {
434    getDiagnostics().Report(diag::err_fe_unable_to_open_output)
435      << OutputPath << Error;
436    return 0;
437  }
438
439  // Add the output file -- but don't try to remove "-", since this means we are
440  // using stdin.
441  addOutputFile(OutputFile((OutputPathName != "-") ? OutputPathName : "",
442                TempPathName, OS));
443
444  return OS;
445}
446
447llvm::raw_fd_ostream *
448CompilerInstance::createOutputFile(StringRef OutputPath,
449                                   std::string &Error,
450                                   bool Binary,
451                                   bool RemoveFileOnSignal,
452                                   StringRef InFile,
453                                   StringRef Extension,
454                                   bool UseTemporary,
455                                   std::string *ResultPathName,
456                                   std::string *TempPathName) {
457  std::string OutFile, TempFile;
458  if (!OutputPath.empty()) {
459    OutFile = OutputPath;
460  } else if (InFile == "-") {
461    OutFile = "-";
462  } else if (!Extension.empty()) {
463    llvm::sys::Path Path(InFile);
464    Path.eraseSuffix();
465    Path.appendSuffix(Extension);
466    OutFile = Path.str();
467  } else {
468    OutFile = "-";
469  }
470
471  llvm::OwningPtr<llvm::raw_fd_ostream> OS;
472  std::string OSFile;
473
474  if (UseTemporary && OutFile != "-") {
475    llvm::sys::Path OutPath(OutFile);
476    // Only create the temporary if we can actually write to OutPath, otherwise
477    // we want to fail early.
478    bool Exists;
479    if ((llvm::sys::fs::exists(OutPath.str(), Exists) || !Exists) ||
480        (OutPath.isRegularFile() && OutPath.canWrite())) {
481      // Create a temporary file.
482      llvm::SmallString<128> TempPath;
483      TempPath = OutFile;
484      TempPath += "-%%%%%%%%";
485      int fd;
486      if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
487                               /*makeAbsolute=*/false) == llvm::errc::success) {
488        OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
489        OSFile = TempFile = TempPath.str();
490      }
491    }
492  }
493
494  if (!OS) {
495    OSFile = OutFile;
496    OS.reset(
497      new llvm::raw_fd_ostream(OSFile.c_str(), Error,
498                               (Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
499    if (!Error.empty())
500      return 0;
501  }
502
503  // Make sure the out stream file gets removed if we crash.
504  if (RemoveFileOnSignal)
505    llvm::sys::RemoveFileOnSignal(llvm::sys::Path(OSFile));
506
507  if (ResultPathName)
508    *ResultPathName = OutFile;
509  if (TempPathName)
510    *TempPathName = TempFile;
511
512  return OS.take();
513}
514
515// Initialization Utilities
516
517bool CompilerInstance::InitializeSourceManager(StringRef InputFile) {
518  return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(),
519                                 getSourceManager(), getFrontendOpts());
520}
521
522bool CompilerInstance::InitializeSourceManager(StringRef InputFile,
523                                               Diagnostic &Diags,
524                                               FileManager &FileMgr,
525                                               SourceManager &SourceMgr,
526                                               const FrontendOptions &Opts) {
527  // Figure out where to get and map in the main file, unless it's already
528  // been created (e.g., by a precompiled preamble).
529  if (!SourceMgr.getMainFileID().isInvalid()) {
530    // Do nothing: the main file has already been set.
531  } else if (InputFile != "-") {
532    const FileEntry *File = FileMgr.getFile(InputFile);
533    if (!File) {
534      Diags.Report(diag::err_fe_error_reading) << InputFile;
535      return false;
536    }
537    SourceMgr.createMainFileID(File);
538  } else {
539    llvm::OwningPtr<llvm::MemoryBuffer> SB;
540    if (llvm::MemoryBuffer::getSTDIN(SB)) {
541      // FIXME: Give ec.message() in this diag.
542      Diags.Report(diag::err_fe_error_reading_stdin);
543      return false;
544    }
545    const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(),
546                                                   SB->getBufferSize(), 0);
547    SourceMgr.createMainFileID(File);
548    SourceMgr.overrideFileContents(File, SB.take());
549  }
550
551  assert(!SourceMgr.getMainFileID().isInvalid() &&
552         "Couldn't establish MainFileID!");
553  return true;
554}
555
556// High-Level Operations
557
558bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
559  assert(hasDiagnostics() && "Diagnostics engine is not initialized!");
560  assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!");
561  assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!");
562
563  // FIXME: Take this as an argument, once all the APIs we used have moved to
564  // taking it as an input instead of hard-coding llvm::errs.
565  raw_ostream &OS = llvm::errs();
566
567  // Create the target instance.
568  setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts()));
569  if (!hasTarget())
570    return false;
571
572  // Inform the target of the language options.
573  //
574  // FIXME: We shouldn't need to do this, the target should be immutable once
575  // created. This complexity should be lifted elsewhere.
576  getTarget().setForcedLangOptions(getLangOpts());
577
578  // Validate/process some options.
579  if (getHeaderSearchOpts().Verbose)
580    OS << "clang -cc1 version " CLANG_VERSION_STRING
581       << " based upon " << PACKAGE_STRING
582       << " hosted on " << llvm::sys::getHostTriple() << "\n";
583
584  if (getFrontendOpts().ShowTimers)
585    createFrontendTimer();
586
587  if (getFrontendOpts().ShowStats)
588    llvm::EnableStatistics();
589
590  for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
591    const std::string &InFile = getFrontendOpts().Inputs[i].second;
592
593    // Reset the ID tables if we are reusing the SourceManager.
594    if (hasSourceManager())
595      getSourceManager().clearIDTables();
596
597    if (Act.BeginSourceFile(*this, InFile, getFrontendOpts().Inputs[i].first)) {
598      Act.Execute();
599      Act.EndSourceFile();
600    }
601  }
602
603  if (getDiagnosticOpts().ShowCarets) {
604    // We can have multiple diagnostics sharing one diagnostic client.
605    // Get the total number of warnings/errors from the client.
606    unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings();
607    unsigned NumErrors = getDiagnostics().getClient()->getNumErrors();
608
609    if (NumWarnings)
610      OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s");
611    if (NumWarnings && NumErrors)
612      OS << " and ";
613    if (NumErrors)
614      OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s");
615    if (NumWarnings || NumErrors)
616      OS << " generated.\n";
617  }
618
619  if (getFrontendOpts().ShowStats && hasFileManager()) {
620    getFileManager().PrintStats();
621    OS << "\n";
622  }
623
624  return !getDiagnostics().getClient()->getNumErrors();
625}
626
627ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
628                                       IdentifierInfo &ModuleName,
629                                       SourceLocation ModuleNameLoc) {
630  // Determine what file we're searching from.
631  SourceManager &SourceMgr = getSourceManager();
632  SourceLocation ExpandedImportLoc = SourceMgr.getExpansionLoc(ImportLoc);
633  const FileEntry *CurFile
634    = SourceMgr.getFileEntryForID(SourceMgr.getFileID(ExpandedImportLoc));
635  if (!CurFile)
636    CurFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
637
638  // Search for a module with the given name.
639  std::string Filename = ModuleName.getName().str();
640  Filename += ".pcm";
641  const DirectoryLookup *CurDir = 0;
642  const FileEntry *ModuleFile
643    = PP->getHeaderSearchInfo().LookupFile(Filename, /*isAngled=*/false,
644                                           /*FromDir=*/0, CurDir, CurFile,
645                                           /*SearchPath=*/0,
646                                           /*RelativePath=*/0);
647  if (!ModuleFile) {
648    getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
649      << ModuleName.getName()
650      << SourceRange(ImportLoc, ModuleNameLoc);
651    return 0;
652  }
653
654  // If we don't already have an ASTReader, create one now.
655  if (!ModuleManager) {
656    std::string Sysroot = getHeaderSearchOpts().Sysroot;
657    const PreprocessorOptions &PPOpts = getPreprocessorOpts();
658    ModuleManager = new ASTReader(getPreprocessor(), &*Context,
659                                  Sysroot.empty() ? "" : Sysroot.c_str(),
660                                  PPOpts.DisablePCHValidation,
661                                  PPOpts.DisableStatCache);
662    ModuleManager->setDeserializationListener(
663      getASTConsumer().GetASTDeserializationListener());
664    getASTContext().setASTMutationListener(
665      getASTConsumer().GetASTMutationListener());
666    llvm::OwningPtr<ExternalASTSource> Source;
667    Source.reset(ModuleManager);
668    getASTContext().setExternalSource(Source);
669    ModuleManager->InitializeSema(getSema());
670  }
671
672  // Try to load the module we found.
673  switch (ModuleManager->ReadAST(ModuleFile->getName(),
674                                 serialization::MK_Module)) {
675  case ASTReader::Success:
676    break;
677
678  case ASTReader::IgnorePCH:
679    // FIXME: The ASTReader will already have complained, but can we showhorn
680    // that diagnostic information into a more useful form?
681    return 0;
682
683  case ASTReader::Failure:
684    // Already complained.
685    return 0;
686  }
687
688  // FIXME: The module file's FileEntry makes a poor key indeed!
689  return (ModuleKey)ModuleFile;
690}
691
692