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