clang  9.0.0svn
PrecompiledPreamble.cpp
Go to the documentation of this file.
1 //===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Helper class to build precompiled preamble.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "clang/AST/DeclObjC.h"
15 #include "clang/Basic/TargetInfo.h"
20 #include "clang/Lex/Lexer.h"
21 #include "clang/Lex/Preprocessor.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/ADT/StringSet.h"
26 #include "llvm/Config/llvm-config.h"
27 #include "llvm/Support/CrashRecoveryContext.h"
28 #include "llvm/Support/FileSystem.h"
29 #include "llvm/Support/Mutex.h"
30 #include "llvm/Support/MutexGuard.h"
31 #include "llvm/Support/Process.h"
32 #include "llvm/Support/VirtualFileSystem.h"
33 #include <limits>
34 #include <utility>
35 
36 using namespace clang;
37 
38 namespace {
39 
40 StringRef getInMemoryPreamblePath() {
41 #if defined(LLVM_ON_UNIX)
42  return "/__clang_tmp/___clang_inmemory_preamble___";
43 #elif defined(_WIN32)
44  return "C:\\__clang_tmp\\___clang_inmemory_preamble___";
45 #else
46 #warning "Unknown platform. Defaulting to UNIX-style paths for in-memory PCHs"
47  return "/__clang_tmp/___clang_inmemory_preamble___";
48 #endif
49 }
50 
52 createVFSOverlayForPreamblePCH(StringRef PCHFilename,
53  std::unique_ptr<llvm::MemoryBuffer> PCHBuffer,
55  // We want only the PCH file from the real filesystem to be available,
56  // so we create an in-memory VFS with just that and overlay it on top.
58  new llvm::vfs::InMemoryFileSystem());
59  PCHFS->addFile(PCHFilename, 0, std::move(PCHBuffer));
61  new llvm::vfs::OverlayFileSystem(VFS));
62  Overlay->pushOverlay(PCHFS);
63  return Overlay;
64 }
65 
66 class PreambleDependencyCollector : public DependencyCollector {
67 public:
68  // We want to collect all dependencies for correctness. Avoiding the real
69  // system dependencies (e.g. stl from /usr/lib) would probably be a good idea,
70  // but there is no way to distinguish between those and the ones that can be
71  // spuriously added by '-isystem' (e.g. to suppress warnings from those
72  // headers).
73  bool needSystemDependencies() override { return true; }
74 };
75 
76 /// Keeps a track of files to be deleted in destructor.
77 class TemporaryFiles {
78 public:
79  // A static instance to be used by all clients.
80  static TemporaryFiles &getInstance();
81 
82 private:
83  // Disallow constructing the class directly.
84  TemporaryFiles() = default;
85  // Disallow copy.
86  TemporaryFiles(const TemporaryFiles &) = delete;
87 
88 public:
89  ~TemporaryFiles();
90 
91  /// Adds \p File to a set of tracked files.
92  void addFile(StringRef File);
93 
94  /// Remove \p File from disk and from the set of tracked files.
95  void removeFile(StringRef File);
96 
97 private:
98  llvm::sys::SmartMutex<false> Mutex;
99  llvm::StringSet<> Files;
100 };
101 
102 TemporaryFiles &TemporaryFiles::getInstance() {
103  static TemporaryFiles Instance;
104  return Instance;
105 }
106 
107 TemporaryFiles::~TemporaryFiles() {
108  llvm::MutexGuard Guard(Mutex);
109  for (const auto &File : Files)
110  llvm::sys::fs::remove(File.getKey());
111 }
112 
113 void TemporaryFiles::addFile(StringRef File) {
114  llvm::MutexGuard Guard(Mutex);
115  auto IsInserted = Files.insert(File).second;
116  (void)IsInserted;
117  assert(IsInserted && "File has already been added");
118 }
119 
120 void TemporaryFiles::removeFile(StringRef File) {
121  llvm::MutexGuard Guard(Mutex);
122  auto WasPresent = Files.erase(File);
123  (void)WasPresent;
124  assert(WasPresent && "File was not tracked");
125  llvm::sys::fs::remove(File);
126 }
127 
128 class PrecompilePreambleAction : public ASTFrontendAction {
129 public:
130  PrecompilePreambleAction(std::string *InMemStorage,
131  PreambleCallbacks &Callbacks)
132  : InMemStorage(InMemStorage), Callbacks(Callbacks) {}
133 
134  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
135  StringRef InFile) override;
136 
137  bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
138 
139  void setEmittedPreamblePCH(ASTWriter &Writer) {
140  this->HasEmittedPreamblePCH = true;
141  Callbacks.AfterPCHEmitted(Writer);
142  }
143 
144  bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
145  bool hasCodeCompletionSupport() const override { return false; }
146  bool hasASTFileSupport() const override { return false; }
147  TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
148 
149 private:
150  friend class PrecompilePreambleConsumer;
151 
152  bool HasEmittedPreamblePCH = false;
153  std::string *InMemStorage;
154  PreambleCallbacks &Callbacks;
155 };
156 
157 class PrecompilePreambleConsumer : public PCHGenerator {
158 public:
159  PrecompilePreambleConsumer(PrecompilePreambleAction &Action,
160  const Preprocessor &PP,
161  InMemoryModuleCache &ModuleCache,
162  StringRef isysroot,
163  std::unique_ptr<raw_ostream> Out)
164  : PCHGenerator(PP, ModuleCache, "", isysroot,
165  std::make_shared<PCHBuffer>(),
166  ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
167  /*AllowASTWithErrors=*/true),
168  Action(Action), Out(std::move(Out)) {}
169 
170  bool HandleTopLevelDecl(DeclGroupRef DG) override {
171  Action.Callbacks.HandleTopLevelDecl(DG);
172  return true;
173  }
174 
175  void HandleTranslationUnit(ASTContext &Ctx) override {
177  if (!hasEmittedPCH())
178  return;
179 
180  // Write the generated bitstream to "Out".
181  *Out << getPCH();
182  // Make sure it hits disk now.
183  Out->flush();
184  // Free the buffer.
186  getPCH() = std::move(Empty);
187 
188  Action.setEmittedPreamblePCH(getWriter());
189  }
190 
191 private:
192  PrecompilePreambleAction &Action;
193  std::unique_ptr<raw_ostream> Out;
194 };
195 
196 std::unique_ptr<ASTConsumer>
197 PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
198  StringRef InFile) {
199  std::string Sysroot;
201  return nullptr;
202 
203  std::unique_ptr<llvm::raw_ostream> OS;
204  if (InMemStorage) {
205  OS = llvm::make_unique<llvm::raw_string_ostream>(*InMemStorage);
206  } else {
207  std::string OutputFile;
208  OS = GeneratePCHAction::CreateOutputFile(CI, InFile, OutputFile);
209  }
210  if (!OS)
211  return nullptr;
212 
214  Sysroot.clear();
215 
216  return llvm::make_unique<PrecompilePreambleConsumer>(
217  *this, CI.getPreprocessor(), CI.getModuleCache(), Sysroot, std::move(OS));
218 }
219 
220 template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
221  if (!Val)
222  return false;
223  Output = std::move(*Val);
224  return true;
225 }
226 
227 } // namespace
228 
230  llvm::MemoryBuffer *Buffer,
231  unsigned MaxLines) {
232  return Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines);
233 }
234 
235 llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
236  const CompilerInvocation &Invocation,
237  const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
238  DiagnosticsEngine &Diagnostics,
240  std::shared_ptr<PCHContainerOperations> PCHContainerOps, bool StoreInMemory,
241  PreambleCallbacks &Callbacks) {
242  assert(VFS && "VFS is null");
243 
244  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
245  FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
246  PreprocessorOptions &PreprocessorOpts =
247  PreambleInvocation->getPreprocessorOpts();
248 
250  if (!StoreInMemory) {
251  // Create a temporary file for the precompiled preamble. In rare
252  // circumstances, this can fail.
253  llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile =
254  PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile();
255  if (!PreamblePCHFile)
257  TempFile = std::move(*PreamblePCHFile);
258  }
259 
260  PCHStorage Storage = StoreInMemory ? PCHStorage(InMemoryPreamble())
261  : PCHStorage(std::move(*TempFile));
262 
263  // Save the preamble text for later; we'll need to compare against it for
264  // subsequent reparses.
265  std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
266  MainFileBuffer->getBufferStart() +
267  Bounds.Size);
268  bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
269 
270  // Tell the compiler invocation to generate a temporary precompiled header.
271  FrontendOpts.ProgramAction = frontend::GeneratePCH;
272  FrontendOpts.OutputFile = StoreInMemory ? getInMemoryPreamblePath()
273  : Storage.asFile().getFilePath();
274  PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
275  PreprocessorOpts.PrecompiledPreambleBytes.second = false;
276  // Inform preprocessor to record conditional stack when building the preamble.
277  PreprocessorOpts.GeneratePreamble = true;
278 
279  // Create the compiler instance to use for building the precompiled preamble.
280  std::unique_ptr<CompilerInstance> Clang(
281  new CompilerInstance(std::move(PCHContainerOps)));
282 
283  // Recover resources if we crash before exiting this method.
284  llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
285  Clang.get());
286 
287  Clang->setInvocation(std::move(PreambleInvocation));
288  Clang->setDiagnostics(&Diagnostics);
289 
290  // Create the target instance.
291  Clang->setTarget(TargetInfo::CreateTargetInfo(
292  Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
293  if (!Clang->hasTarget())
295 
296  // Inform the target of the language options.
297  //
298  // FIXME: We shouldn't need to do this, the target should be immutable once
299  // created. This complexity should be lifted elsewhere.
300  Clang->getTarget().adjust(Clang->getLangOpts());
301 
302  if (Clang->getFrontendOpts().Inputs.size() != 1 ||
303  Clang->getFrontendOpts().Inputs[0].getKind().getFormat() !=
305  Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() ==
308  }
309 
310  // Clear out old caches and data.
311  Diagnostics.Reset();
312  ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
313 
314  VFS =
315  createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
316 
317  // Create a file manager object to provide access to and cache the filesystem.
318  Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
319 
320  // Create the source manager.
321  Clang->setSourceManager(
322  new SourceManager(Diagnostics, Clang->getFileManager()));
323 
324  auto PreambleDepCollector = std::make_shared<PreambleDependencyCollector>();
325  Clang->addDependencyCollector(PreambleDepCollector);
326 
327  // Remap the main source file to the preamble buffer.
328  StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
329  auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
330  MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
331  if (PreprocessorOpts.RetainRemappedFileBuffers) {
332  // MainFileBuffer will be deleted by unique_ptr after leaving the method.
333  PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
334  } else {
335  // In that case, remapped buffer will be deleted by CompilerInstance on
336  // BeginSourceFile, so we call release() to avoid double deletion.
337  PreprocessorOpts.addRemappedFile(MainFilePath,
338  PreambleInputBuffer.release());
339  }
340 
341  std::unique_ptr<PrecompilePreambleAction> Act;
342  Act.reset(new PrecompilePreambleAction(
343  StoreInMemory ? &Storage.asMemory().Data : nullptr, Callbacks));
344  Callbacks.BeforeExecute(*Clang);
345  if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
347 
348  std::unique_ptr<PPCallbacks> DelegatedPPCallbacks =
349  Callbacks.createPPCallbacks();
350  if (DelegatedPPCallbacks)
351  Clang->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks));
352  if (auto CommentHandler = Callbacks.getCommentHandler())
353  Clang->getPreprocessor().addCommentHandler(CommentHandler);
354 
355  Act->Execute();
356 
357  // Run the callbacks.
358  Callbacks.AfterExecute(*Clang);
359 
360  Act->EndSourceFile();
361 
362  if (!Act->hasEmittedPreamblePCH())
364 
365  // Keep track of all of the files that the source manager knows about,
366  // so we can verify whether they have changed or not.
367  llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
368 
369  SourceManager &SourceMgr = Clang->getSourceManager();
370  for (auto &Filename : PreambleDepCollector->getDependencies()) {
371  const FileEntry *File = Clang->getFileManager().getFile(Filename);
372  if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
373  continue;
374  if (time_t ModTime = File->getModificationTime()) {
375  FilesInPreamble[File->getName()] =
376  PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
377  ModTime);
378  } else {
379  const llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
380  FilesInPreamble[File->getName()] =
381  PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
382  }
383  }
384 
385  return PrecompiledPreamble(std::move(Storage), std::move(PreambleBytes),
386  PreambleEndsAtStartOfLine,
387  std::move(FilesInPreamble));
388 }
389 
391  return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
392 }
393 
395  switch (Storage.getKind()) {
396  case PCHStorage::Kind::Empty:
397  assert(false && "Calling getSize() on invalid PrecompiledPreamble. "
398  "Was it std::moved?");
399  return 0;
400  case PCHStorage::Kind::InMemory:
401  return Storage.asMemory().Data.size();
402  case PCHStorage::Kind::TempFile: {
403  uint64_t Result;
404  if (llvm::sys::fs::file_size(Storage.asFile().getFilePath(), Result))
405  return 0;
406 
407  assert(Result <= std::numeric_limits<std::size_t>::max() &&
408  "file size did not fit into size_t");
409  return Result;
410  }
411  }
412  llvm_unreachable("Unhandled storage kind");
413 }
414 
416  const llvm::MemoryBuffer *MainFileBuffer,
417  PreambleBounds Bounds,
418  llvm::vfs::FileSystem *VFS) const {
419 
420  assert(
421  Bounds.Size <= MainFileBuffer->getBufferSize() &&
422  "Buffer is too large. Bounds were calculated from a different buffer?");
423 
424  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
425  PreprocessorOptions &PreprocessorOpts =
426  PreambleInvocation->getPreprocessorOpts();
427 
428  // We've previously computed a preamble. Check whether we have the same
429  // preamble now that we did before, and that there's enough space in
430  // the main-file buffer within the precompiled preamble to fit the
431  // new main file.
432  if (PreambleBytes.size() != Bounds.Size ||
433  PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
434  !std::equal(PreambleBytes.begin(), PreambleBytes.end(),
435  MainFileBuffer->getBuffer().begin()))
436  return false;
437  // The preamble has not changed. We may be able to re-use the precompiled
438  // preamble.
439 
440  // Check that none of the files used by the preamble have changed.
441  // First, make a record of those files that have been overridden via
442  // remapping or unsaved_files.
443  std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
444  for (const auto &R : PreprocessorOpts.RemappedFiles) {
445  llvm::vfs::Status Status;
446  if (!moveOnNoError(VFS->status(R.second), Status)) {
447  // If we can't stat the file we're remapping to, assume that something
448  // horrible happened.
449  return false;
450  }
451 
452  OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
453  Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
454  }
455 
456  // OverridenFileBuffers tracks only the files not found in VFS.
457  llvm::StringMap<PreambleFileHash> OverridenFileBuffers;
458  for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
459  const PrecompiledPreamble::PreambleFileHash PreambleHash =
460  PreambleFileHash::createForMemoryBuffer(RB.second);
461  llvm::vfs::Status Status;
462  if (moveOnNoError(VFS->status(RB.first), Status))
463  OverriddenFiles[Status.getUniqueID()] = PreambleHash;
464  else
465  OverridenFileBuffers[RB.first] = PreambleHash;
466  }
467 
468  // Check whether anything has changed.
469  for (const auto &F : FilesInPreamble) {
470  auto OverridenFileBuffer = OverridenFileBuffers.find(F.first());
471  if (OverridenFileBuffer != OverridenFileBuffers.end()) {
472  // The file's buffer was remapped and the file was not found in VFS.
473  // Check whether it matches up with the previous mapping.
474  if (OverridenFileBuffer->second != F.second)
475  return false;
476  continue;
477  }
478 
479  llvm::vfs::Status Status;
480  if (!moveOnNoError(VFS->status(F.first()), Status)) {
481  // If the file's buffer is not remapped and we can't stat it,
482  // assume that something horrible happened.
483  return false;
484  }
485 
486  std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
487  OverriddenFiles.find(Status.getUniqueID());
488  if (Overridden != OverriddenFiles.end()) {
489  // This file was remapped; check whether the newly-mapped file
490  // matches up with the previous mapping.
491  if (Overridden->second != F.second)
492  return false;
493  continue;
494  }
495 
496  // Neither the file's buffer nor the file itself was remapped;
497  // check whether it has changed on disk.
498  if (Status.getSize() != uint64_t(F.second.Size) ||
499  llvm::sys::toTimeT(Status.getLastModificationTime()) !=
500  F.second.ModTime)
501  return false;
502  }
503  return true;
504 }
505 
508  llvm::MemoryBuffer *MainFileBuffer) const {
509  PreambleBounds Bounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
510  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
511 }
512 
515  llvm::MemoryBuffer *MainFileBuffer) const {
516  auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), MainFileBuffer, 0);
517  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
518 }
519 
521  PCHStorage Storage, std::vector<char> PreambleBytes,
522  bool PreambleEndsAtStartOfLine,
523  llvm::StringMap<PreambleFileHash> FilesInPreamble)
524  : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
525  PreambleBytes(std::move(PreambleBytes)),
526  PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
527  assert(this->Storage.getKind() != PCHStorage::Kind::Empty);
528 }
529 
530 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
531 PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
532  // FIXME: This is a hack so that we can override the preamble file during
533  // crash-recovery testing, which is the only case where the preamble files
534  // are not necessarily cleaned up.
535  const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
536  if (TmpFile)
537  return TempPCHFile::createFromCustomPath(TmpFile);
538  return TempPCHFile::createInSystemTempDir("preamble", "pch");
539 }
540 
541 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
542 PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
543  StringRef Suffix) {
545  // Using a version of createTemporaryFile with a file descriptor guarantees
546  // that we would never get a race condition in a multi-threaded setting
547  // (i.e., multiple threads getting the same temporary path).
548  int FD;
549  auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File);
550  if (EC)
551  return EC;
552  // We only needed to make sure the file exists, close the file right away.
553  llvm::sys::Process::SafelyCloseFileDescriptor(FD);
554  return TempPCHFile(std::move(File).str());
555 }
556 
557 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
558 PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
559  return TempPCHFile(Path.str());
560 }
561 
562 PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
563  : FilePath(std::move(FilePath)) {
564  TemporaryFiles::getInstance().addFile(*this->FilePath);
565 }
566 
567 PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
568  FilePath = std::move(Other.FilePath);
569  Other.FilePath = None;
570 }
571 
572 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
573 operator=(TempPCHFile &&Other) {
574  RemoveFileIfPresent();
575 
576  FilePath = std::move(Other.FilePath);
577  Other.FilePath = None;
578  return *this;
579 }
580 
581 PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
582 
583 void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
584  if (FilePath) {
585  TemporaryFiles::getInstance().removeFile(*FilePath);
586  FilePath = None;
587  }
588 }
589 
590 llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
591  assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
592  return *FilePath;
593 }
594 
595 PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File)
596  : StorageKind(Kind::TempFile) {
597  new (&asFile()) TempPCHFile(std::move(File));
598 }
599 
600 PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory)
601  : StorageKind(Kind::InMemory) {
602  new (&asMemory()) InMemoryPreamble(std::move(Memory));
603 }
604 
605 PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() {
606  *this = std::move(Other);
607 }
608 
609 PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage::
610 operator=(PCHStorage &&Other) {
611  destroy();
612 
613  StorageKind = Other.StorageKind;
614  switch (StorageKind) {
615  case Kind::Empty:
616  // do nothing;
617  break;
618  case Kind::TempFile:
619  new (&asFile()) TempPCHFile(std::move(Other.asFile()));
620  break;
621  case Kind::InMemory:
622  new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory()));
623  break;
624  }
625 
626  Other.setEmpty();
627  return *this;
628 }
629 
630 PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); }
631 
632 PrecompiledPreamble::PCHStorage::Kind
634  return StorageKind;
635 }
636 
637 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() {
638  assert(getKind() == Kind::TempFile);
639  return *reinterpret_cast<TempPCHFile *>(Storage.buffer);
640 }
641 
642 const PrecompiledPreamble::TempPCHFile &
643 PrecompiledPreamble::PCHStorage::asFile() const {
644  return const_cast<PCHStorage *>(this)->asFile();
645 }
646 
647 PrecompiledPreamble::InMemoryPreamble &
648 PrecompiledPreamble::PCHStorage::asMemory() {
649  assert(getKind() == Kind::InMemory);
650  return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer);
651 }
652 
653 const PrecompiledPreamble::InMemoryPreamble &
654 PrecompiledPreamble::PCHStorage::asMemory() const {
655  return const_cast<PCHStorage *>(this)->asMemory();
656 }
657 
658 void PrecompiledPreamble::PCHStorage::destroy() {
659  switch (StorageKind) {
660  case Kind::Empty:
661  return;
662  case Kind::TempFile:
663  asFile().~TempPCHFile();
664  return;
665  case Kind::InMemory:
666  asMemory().~InMemoryPreamble();
667  return;
668  }
669 }
670 
671 void PrecompiledPreamble::PCHStorage::setEmpty() {
672  destroy();
673  StorageKind = Kind::Empty;
674 }
675 
676 PrecompiledPreamble::PreambleFileHash
677 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
678  time_t ModTime) {
679  PreambleFileHash Result;
680  Result.Size = Size;
681  Result.ModTime = ModTime;
682  Result.MD5 = {};
683  return Result;
684 }
685 
686 PrecompiledPreamble::PreambleFileHash
687 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
688  const llvm::MemoryBuffer *Buffer) {
689  PreambleFileHash Result;
690  Result.Size = Buffer->getBufferSize();
691  Result.ModTime = 0;
692 
693  llvm::MD5 MD5Ctx;
694  MD5Ctx.update(Buffer->getBuffer().data());
695  MD5Ctx.final(Result.MD5);
696 
697  return Result;
698 }
699 
700 void PrecompiledPreamble::configurePreamble(
703  llvm::MemoryBuffer *MainFileBuffer) const {
704  assert(VFS);
705 
706  auto &PreprocessorOpts = CI.getPreprocessorOpts();
707 
708  // Remap main file to point to MainFileBuffer.
709  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
710  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
711 
712  // Configure ImpicitPCHInclude.
713  PreprocessorOpts.PrecompiledPreambleBytes.first = Bounds.Size;
714  PreprocessorOpts.PrecompiledPreambleBytes.second =
716  PreprocessorOpts.DisablePCHValidation = true;
717 
718  setupPreambleStorage(Storage, PreprocessorOpts, VFS);
719 }
720 
721 void PrecompiledPreamble::setupPreambleStorage(
722  const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
724  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
725  const TempPCHFile &PCHFile = Storage.asFile();
726  PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
727 
728  // Make sure we can access the PCH file even if we're using a VFS
730  llvm::vfs::getRealFileSystem();
731  auto PCHPath = PCHFile.getFilePath();
732  if (VFS == RealFS || VFS->exists(PCHPath))
733  return;
734  auto Buf = RealFS->getBufferForFile(PCHPath);
735  if (!Buf) {
736  // We can't read the file even from RealFS, this is clearly an error,
737  // but we'll just leave the current VFS as is and let clang's code
738  // figure out what to do with missing PCH.
739  return;
740  }
741 
742  // We have a slight inconsistency here -- we're using the VFS to
743  // read files, but the PCH was generated in the real file system.
744  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
745  } else {
746  assert(Storage.getKind() == PCHStorage::Kind::InMemory);
747  // For in-memory preamble, we have to provide a VFS overlay that makes it
748  // accessible.
749  StringRef PCHPath = getInMemoryPreamblePath();
750  PreprocessorOpts.ImplicitPCHInclude = PCHPath;
751 
752  auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data);
753  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
754  }
755 }
756 
761 std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
762  return nullptr;
763 }
765 
766 static llvm::ManagedStatic<BuildPreambleErrorCategory> BuildPreambleErrCategory;
767 
769  return std::error_code(static_cast<int>(Error), *BuildPreambleErrCategory);
770 }
771 
772 const char *BuildPreambleErrorCategory::name() const noexcept {
773  return "build-preamble.error";
774 }
775 
776 std::string BuildPreambleErrorCategory::message(int condition) const {
777  switch (static_cast<BuildPreambleError>(condition)) {
779  return "Could not create temporary file for PCH";
781  return "CreateTargetInfo() return null";
783  return "BeginSourceFile() return an error";
785  return "Could not emit PCH";
787  return "Command line arguments must contain exactly one source file";
788  }
789  llvm_unreachable("unexpected BuildPreambleError");
790 }
std::size_t getSize() const
Returns the size, in bytes, that preamble takes on disk or in memory.
Describes the bounds (start, size) of the preamble and a flag required by PreprocessorOptions::Precom...
Definition: Lexer.h:58
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:116
time_t getModificationTime() const
Definition: FileManager.h:89
bool CanReuse(const CompilerInvocation &Invocation, const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, llvm::vfs::FileSystem *VFS) const
Check whether PrecompiledPreamble can be reused for the new contents(MainFileBuffer) of the main file...
An interface for collecting the dependencies of a compilation.
Definition: Utils.h:81
The translation unit is a prefix to a translation unit, and is not complete.
Definition: LangOptions.h:368
InMemoryModuleCache & getModuleCache() const
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
void addRemappedFile(StringRef From, StringRef To)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:154
void HandleTranslationUnit(ASTContext &Ctx) override
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
Definition: GeneratePCH.cpp:41
Definition: Format.h:2261
static bool moveOnNoError(llvm::ErrorOr< T > Val, T &Output)
Definition: ASTUnit.cpp:146
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
Definition: opencl-c-base.h:40
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
unsigned RelocatablePCH
When generating PCH files, instruct the AST writer to create relocatable PCH files.
static bool ComputeASTConsumerArguments(CompilerInstance &CI, std::string &Sysroot)
Compute the AST consumer arguments that will be used to create the PCHGenerator instance returned by ...
static llvm::ManagedStatic< BuildPreambleErrorCategory > BuildPreambleErrCategory
std::error_code make_error_code(BuildPreambleError Error)
FrontendOptions & getFrontendOpts()
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:148
bool RetainRemappedFileBuffers
Whether the compiler instance should retain (i.e., not free) the buffers associated with remapped fil...
void OverridePreamble(CompilerInvocation &CI, IntrusiveRefCntPtr< llvm::vfs::FileSystem > &VFS, llvm::MemoryBuffer *MainFileBuffer) const
Configure CI to use this preamble.
void Reset()
Reset the state of the diagnostic object to its initial configuration.
Definition: Diagnostic.cpp:121
FrontendOptions & getFrontendOpts()
bool PreambleEndsAtStartOfLine
Whether the preamble ends at the start of a new line.
Definition: Lexer.h:66
A set of callbacks to gather useful information while building a preamble.
StringRef Filename
Definition: Format.cpp:1709
const char * name() const noexcept override
PreambleBounds getBounds() const
PreambleBounds used to build the preamble.
void AddImplicitPreamble(CompilerInvocation &CI, IntrusiveRefCntPtr< llvm::vfs::FileSystem > &VFS, llvm::MemoryBuffer *MainFileBuffer) const
Changes options inside CI to use PCH from this preamble.
static PreambleBounds ComputePreamble(StringRef Buffer, const LangOptions &LangOpts, unsigned MaxLines=0)
Compute the preamble of the given file.
Definition: Lexer.cpp:573
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
Defines the clang::Preprocessor interface.
ASTEdit remove(RangeSelector S)
Removes the source selected by S.
Definition: Transformer.h:209
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr< TargetOptions > &Opts)
Construct a target for the given options.
Definition: Targets.cpp:615
bool GeneratePreamble
True indicates that a preamble is being generated.
PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, llvm::MemoryBuffer *Buffer, unsigned MaxLines)
Runs lexer to compute suggested preamble bounds.
The result type of a method or function.
In-memory cache for modules.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
StringRef getName() const
Definition: FileManager.h:83
virtual CommentHandler * getCommentHandler()
The returned CommentHandler will be added to the preprocessor if not null.
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
LLVM IR: we accept this so that we can run the optimizer on it, and compile it to assembly or object ...
std::vector< FrontendInputFile > Inputs
The input files and their types.
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:59
void ProcessWarningOptions(DiagnosticsEngine &Diags, const DiagnosticOptions &Opts, bool ReportDiags=true)
ProcessWarningOptions - Initialize the diagnostic client and process the warning options specified on...
Definition: Warnings.cpp:43
Abstract base class to use for AST consumer-based frontend actions.
virtual void BeforeExecute(CompilerInstance &CI)
Called before FrontendAction::BeginSourceFile.
virtual void AfterPCHEmitted(ASTWriter &Writer)
Called after PCH has been emitted.
PrecompiledPreamble(PrecompiledPreamble &&)=default
std::string message(int condition) const override
Dataflow Directional Tag Classes.
A class holding a PCH and all information to check whether it is valid to reuse the PCH for the subse...
PreprocessorOptions & getPreprocessorOpts()
off_t getSize() const
Definition: FileManager.h:86
IntrusiveRefCntPtr< llvm::vfs::FileSystem > createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags)
const llvm::MemoryBuffer * getMemoryBufferForFile(const FileEntry *File, bool *Invalid=nullptr)
Retrieve the memory buffer associated with the given file.
FileID getMainFileID() const
Returns the FileID of the main source file.
Helper class for holding the data necessary to invoke the compiler.
FrontendOptions - Options for controlling the behavior of the frontend.
virtual void AfterExecute(CompilerInstance &CI)
Called after FrontendAction::Execute(), but before FrontendAction::EndSourceFile().
static llvm::ErrorOr< PrecompiledPreamble > Build(const CompilerInvocation &Invocation, const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, std::shared_ptr< PCHContainerOperations > PCHContainerOps, bool StoreInMemory, PreambleCallbacks &Callbacks)
Try to build PrecompiledPreamble for Invocation.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
unsigned Size
Size of the preamble in bytes.
Definition: Lexer.h:60
Generate pre-compiled header.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
TranslationUnitKind
Describes the kind of translation unit being processed.
Definition: LangOptions.h:362
Writes an AST file containing the contents of a translation unit.
Definition: ASTWriter.h:103
std::pair< unsigned, bool > PrecompiledPreambleBytes
If non-zero, the implicit PCH include is actually a precompiled preamble that covers this number of b...
Defines the clang::TargetInfo interface.
__DEVICE__ int max(int __a, int __b)
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:943
Abstract base class that describes a handler that will receive source ranges for each of the comments...
An abstract superclass that describes a custom extension to the module/precompiled header file format...
AST and semantic-analysis consumer that generates a precompiled header from the parsed source code...
Definition: ASTWriter.h:972
static std::unique_ptr< llvm::raw_pwrite_stream > CreateOutputFile(CompilerInstance &CI, StringRef InFile, std::string &OutputFile)
Creates file to write the PCH into and returns a stream to write it into.
#define true
Definition: stdbool.h:16
virtual void HandleTopLevelDecl(DeclGroupRef DG)
Called for each TopLevelDecl.
This class handles loading and caching of source files into memory.
virtual std::unique_ptr< PPCallbacks > createPPCallbacks()
Creates wrapper class for PPCallbacks so we can also process information about includes that are insi...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:124