clang  10.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"
16 #include "clang/Basic/TargetInfo.h"
21 #include "clang/Lex/Lexer.h"
22 #include "clang/Lex/Preprocessor.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include "llvm/ADT/StringSet.h"
27 #include "llvm/Config/llvm-config.h"
28 #include "llvm/Support/CrashRecoveryContext.h"
29 #include "llvm/Support/FileSystem.h"
30 #include "llvm/Support/Process.h"
31 #include "llvm/Support/VirtualFileSystem.h"
32 #include <limits>
33 #include <mutex>
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  std::mutex Mutex;
99  llvm::StringSet<> Files;
100 };
101 
102 TemporaryFiles &TemporaryFiles::getInstance() {
103  static TemporaryFiles Instance;
104  return Instance;
105 }
106 
107 TemporaryFiles::~TemporaryFiles() {
108  std::lock_guard<std::mutex> Guard(Mutex);
109  for (const auto &File : Files)
110  llvm::sys::fs::remove(File.getKey());
111 }
112 
113 void TemporaryFiles::addFile(StringRef File) {
114  std::lock_guard<std::mutex> 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  std::lock_guard<std::mutex> 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 = std::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 std::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  if (llvm::Error Err = Act->Execute())
356  return errorToErrorCode(std::move(Err));
357 
358  // Run the callbacks.
359  Callbacks.AfterExecute(*Clang);
360 
361  Act->EndSourceFile();
362 
363  if (!Act->hasEmittedPreamblePCH())
365 
366  // Keep track of all of the files that the source manager knows about,
367  // so we can verify whether they have changed or not.
368  llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
369 
370  SourceManager &SourceMgr = Clang->getSourceManager();
371  for (auto &Filename : PreambleDepCollector->getDependencies()) {
372  auto FileOrErr = Clang->getFileManager().getFile(Filename);
373  if (!FileOrErr ||
374  *FileOrErr == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
375  continue;
376  auto File = *FileOrErr;
377  if (time_t ModTime = File->getModificationTime()) {
378  FilesInPreamble[File->getName()] =
379  PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
380  ModTime);
381  } else {
382  const llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
383  FilesInPreamble[File->getName()] =
384  PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
385  }
386  }
387 
388  return PrecompiledPreamble(std::move(Storage), std::move(PreambleBytes),
389  PreambleEndsAtStartOfLine,
390  std::move(FilesInPreamble));
391 }
392 
394  return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
395 }
396 
398  switch (Storage.getKind()) {
399  case PCHStorage::Kind::Empty:
400  assert(false && "Calling getSize() on invalid PrecompiledPreamble. "
401  "Was it std::moved?");
402  return 0;
403  case PCHStorage::Kind::InMemory:
404  return Storage.asMemory().Data.size();
405  case PCHStorage::Kind::TempFile: {
406  uint64_t Result;
407  if (llvm::sys::fs::file_size(Storage.asFile().getFilePath(), Result))
408  return 0;
409 
410  assert(Result <= std::numeric_limits<std::size_t>::max() &&
411  "file size did not fit into size_t");
412  return Result;
413  }
414  }
415  llvm_unreachable("Unhandled storage kind");
416 }
417 
419  const llvm::MemoryBuffer *MainFileBuffer,
420  PreambleBounds Bounds,
421  llvm::vfs::FileSystem *VFS) const {
422 
423  assert(
424  Bounds.Size <= MainFileBuffer->getBufferSize() &&
425  "Buffer is too large. Bounds were calculated from a different buffer?");
426 
427  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
428  PreprocessorOptions &PreprocessorOpts =
429  PreambleInvocation->getPreprocessorOpts();
430 
431  // We've previously computed a preamble. Check whether we have the same
432  // preamble now that we did before, and that there's enough space in
433  // the main-file buffer within the precompiled preamble to fit the
434  // new main file.
435  if (PreambleBytes.size() != Bounds.Size ||
436  PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
437  !std::equal(PreambleBytes.begin(), PreambleBytes.end(),
438  MainFileBuffer->getBuffer().begin()))
439  return false;
440  // The preamble has not changed. We may be able to re-use the precompiled
441  // preamble.
442 
443  // Check that none of the files used by the preamble have changed.
444  // First, make a record of those files that have been overridden via
445  // remapping or unsaved_files.
446  std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
447  for (const auto &R : PreprocessorOpts.RemappedFiles) {
448  llvm::vfs::Status Status;
449  if (!moveOnNoError(VFS->status(R.second), Status)) {
450  // If we can't stat the file we're remapping to, assume that something
451  // horrible happened.
452  return false;
453  }
454 
455  OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
456  Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
457  }
458 
459  // OverridenFileBuffers tracks only the files not found in VFS.
460  llvm::StringMap<PreambleFileHash> OverridenFileBuffers;
461  for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
462  const PrecompiledPreamble::PreambleFileHash PreambleHash =
463  PreambleFileHash::createForMemoryBuffer(RB.second);
464  llvm::vfs::Status Status;
465  if (moveOnNoError(VFS->status(RB.first), Status))
466  OverriddenFiles[Status.getUniqueID()] = PreambleHash;
467  else
468  OverridenFileBuffers[RB.first] = PreambleHash;
469  }
470 
471  // Check whether anything has changed.
472  for (const auto &F : FilesInPreamble) {
473  auto OverridenFileBuffer = OverridenFileBuffers.find(F.first());
474  if (OverridenFileBuffer != OverridenFileBuffers.end()) {
475  // The file's buffer was remapped and the file was not found in VFS.
476  // Check whether it matches up with the previous mapping.
477  if (OverridenFileBuffer->second != F.second)
478  return false;
479  continue;
480  }
481 
482  llvm::vfs::Status Status;
483  if (!moveOnNoError(VFS->status(F.first()), Status)) {
484  // If the file's buffer is not remapped and we can't stat it,
485  // assume that something horrible happened.
486  return false;
487  }
488 
489  std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
490  OverriddenFiles.find(Status.getUniqueID());
491  if (Overridden != OverriddenFiles.end()) {
492  // This file was remapped; check whether the newly-mapped file
493  // matches up with the previous mapping.
494  if (Overridden->second != F.second)
495  return false;
496  continue;
497  }
498 
499  // Neither the file's buffer nor the file itself was remapped;
500  // check whether it has changed on disk.
501  if (Status.getSize() != uint64_t(F.second.Size) ||
502  llvm::sys::toTimeT(Status.getLastModificationTime()) !=
503  F.second.ModTime)
504  return false;
505  }
506  return true;
507 }
508 
511  llvm::MemoryBuffer *MainFileBuffer) const {
512  PreambleBounds Bounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
513  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
514 }
515 
518  llvm::MemoryBuffer *MainFileBuffer) const {
519  auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), MainFileBuffer, 0);
520  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
521 }
522 
524  PCHStorage Storage, std::vector<char> PreambleBytes,
525  bool PreambleEndsAtStartOfLine,
526  llvm::StringMap<PreambleFileHash> FilesInPreamble)
527  : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
528  PreambleBytes(std::move(PreambleBytes)),
529  PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
530  assert(this->Storage.getKind() != PCHStorage::Kind::Empty);
531 }
532 
533 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
534 PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
535  // FIXME: This is a hack so that we can override the preamble file during
536  // crash-recovery testing, which is the only case where the preamble files
537  // are not necessarily cleaned up.
538  const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
539  if (TmpFile)
540  return TempPCHFile::createFromCustomPath(TmpFile);
541  return TempPCHFile::createInSystemTempDir("preamble", "pch");
542 }
543 
544 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
545 PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
546  StringRef Suffix) {
548  // Using a version of createTemporaryFile with a file descriptor guarantees
549  // that we would never get a race condition in a multi-threaded setting
550  // (i.e., multiple threads getting the same temporary path).
551  int FD;
552  auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File);
553  if (EC)
554  return EC;
555  // We only needed to make sure the file exists, close the file right away.
556  llvm::sys::Process::SafelyCloseFileDescriptor(FD);
557  return TempPCHFile(std::move(File).str());
558 }
559 
560 llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
561 PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
562  return TempPCHFile(Path.str());
563 }
564 
565 PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
566  : FilePath(std::move(FilePath)) {
567  TemporaryFiles::getInstance().addFile(*this->FilePath);
568 }
569 
570 PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
571  FilePath = std::move(Other.FilePath);
572  Other.FilePath = None;
573 }
574 
575 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
576 operator=(TempPCHFile &&Other) {
577  RemoveFileIfPresent();
578 
579  FilePath = std::move(Other.FilePath);
580  Other.FilePath = None;
581  return *this;
582 }
583 
584 PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
585 
586 void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
587  if (FilePath) {
588  TemporaryFiles::getInstance().removeFile(*FilePath);
589  FilePath = None;
590  }
591 }
592 
593 llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
594  assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
595  return *FilePath;
596 }
597 
598 PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File)
599  : StorageKind(Kind::TempFile) {
600  new (&asFile()) TempPCHFile(std::move(File));
601 }
602 
603 PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory)
604  : StorageKind(Kind::InMemory) {
605  new (&asMemory()) InMemoryPreamble(std::move(Memory));
606 }
607 
608 PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() {
609  *this = std::move(Other);
610 }
611 
612 PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage::
613 operator=(PCHStorage &&Other) {
614  destroy();
615 
616  StorageKind = Other.StorageKind;
617  switch (StorageKind) {
618  case Kind::Empty:
619  // do nothing;
620  break;
621  case Kind::TempFile:
622  new (&asFile()) TempPCHFile(std::move(Other.asFile()));
623  break;
624  case Kind::InMemory:
625  new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory()));
626  break;
627  }
628 
629  Other.setEmpty();
630  return *this;
631 }
632 
633 PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); }
634 
635 PrecompiledPreamble::PCHStorage::Kind
637  return StorageKind;
638 }
639 
640 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() {
641  assert(getKind() == Kind::TempFile);
642  return *reinterpret_cast<TempPCHFile *>(Storage.buffer);
643 }
644 
645 const PrecompiledPreamble::TempPCHFile &
646 PrecompiledPreamble::PCHStorage::asFile() const {
647  return const_cast<PCHStorage *>(this)->asFile();
648 }
649 
650 PrecompiledPreamble::InMemoryPreamble &
651 PrecompiledPreamble::PCHStorage::asMemory() {
652  assert(getKind() == Kind::InMemory);
653  return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer);
654 }
655 
656 const PrecompiledPreamble::InMemoryPreamble &
657 PrecompiledPreamble::PCHStorage::asMemory() const {
658  return const_cast<PCHStorage *>(this)->asMemory();
659 }
660 
661 void PrecompiledPreamble::PCHStorage::destroy() {
662  switch (StorageKind) {
663  case Kind::Empty:
664  return;
665  case Kind::TempFile:
666  asFile().~TempPCHFile();
667  return;
668  case Kind::InMemory:
669  asMemory().~InMemoryPreamble();
670  return;
671  }
672 }
673 
674 void PrecompiledPreamble::PCHStorage::setEmpty() {
675  destroy();
676  StorageKind = Kind::Empty;
677 }
678 
679 PrecompiledPreamble::PreambleFileHash
680 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
681  time_t ModTime) {
682  PreambleFileHash Result;
683  Result.Size = Size;
684  Result.ModTime = ModTime;
685  Result.MD5 = {};
686  return Result;
687 }
688 
689 PrecompiledPreamble::PreambleFileHash
690 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
691  const llvm::MemoryBuffer *Buffer) {
692  PreambleFileHash Result;
693  Result.Size = Buffer->getBufferSize();
694  Result.ModTime = 0;
695 
696  llvm::MD5 MD5Ctx;
697  MD5Ctx.update(Buffer->getBuffer().data());
698  MD5Ctx.final(Result.MD5);
699 
700  return Result;
701 }
702 
703 void PrecompiledPreamble::configurePreamble(
706  llvm::MemoryBuffer *MainFileBuffer) const {
707  assert(VFS);
708 
709  auto &PreprocessorOpts = CI.getPreprocessorOpts();
710 
711  // Remap main file to point to MainFileBuffer.
712  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
713  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
714 
715  // Configure ImpicitPCHInclude.
716  PreprocessorOpts.PrecompiledPreambleBytes.first = Bounds.Size;
717  PreprocessorOpts.PrecompiledPreambleBytes.second =
719  PreprocessorOpts.DisablePCHValidation = true;
720 
721  setupPreambleStorage(Storage, PreprocessorOpts, VFS);
722 }
723 
724 void PrecompiledPreamble::setupPreambleStorage(
725  const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
727  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
728  const TempPCHFile &PCHFile = Storage.asFile();
729  PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
730 
731  // Make sure we can access the PCH file even if we're using a VFS
733  llvm::vfs::getRealFileSystem();
734  auto PCHPath = PCHFile.getFilePath();
735  if (VFS == RealFS || VFS->exists(PCHPath))
736  return;
737  auto Buf = RealFS->getBufferForFile(PCHPath);
738  if (!Buf) {
739  // We can't read the file even from RealFS, this is clearly an error,
740  // but we'll just leave the current VFS as is and let clang's code
741  // figure out what to do with missing PCH.
742  return;
743  }
744 
745  // We have a slight inconsistency here -- we're using the VFS to
746  // read files, but the PCH was generated in the real file system.
747  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
748  } else {
749  assert(Storage.getKind() == PCHStorage::Kind::InMemory);
750  // For in-memory preamble, we have to provide a VFS overlay that makes it
751  // accessible.
752  StringRef PCHPath = getInMemoryPreamblePath();
753  PreprocessorOpts.ImplicitPCHInclude = PCHPath;
754 
755  auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data);
756  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
757  }
758 }
759 
764 std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
765  return nullptr;
766 }
768 
769 static llvm::ManagedStatic<BuildPreambleErrorCategory> BuildPreambleErrCategory;
770 
772  return std::error_code(static_cast<int>(Error), *BuildPreambleErrCategory);
773 }
774 
775 const char *BuildPreambleErrorCategory::name() const noexcept {
776  return "build-preamble.error";
777 }
778 
779 std::string BuildPreambleErrorCategory::message(int condition) const {
780  switch (static_cast<BuildPreambleError>(condition)) {
782  return "Could not create temporary file for PCH";
784  return "CreateTargetInfo() return null";
786  return "BeginSourceFile() return an error";
788  return "Could not emit PCH";
790  return "Command line arguments must contain exactly one source file";
791  }
792  llvm_unreachable("unexpected BuildPreambleError");
793 }
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:171
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:384
InMemoryModuleCache & getModuleCache() const
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
void addRemappedFile(StringRef From, StringRef To)
FileManager & getFileManager() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:160
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:2327
static bool moveOnNoError(llvm::ErrorOr< T > Val, T &Output)
Definition: ASTUnit.cpp:148
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
Definition: opencl-c-base.h:40
__DEVICE__ int max(int __a, int __b)
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:149
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:1756
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:582
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:230
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr< TargetOptions > &Opts)
Construct a target for the given options.
Definition: Targets.cpp:613
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.
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.
std::vector< FrontendInputFile > Inputs
The input files and their types.
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()
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.
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
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:378
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.
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:945
LLVM IR: we accept this so that we can run the optimizer on it, and compile it to assembly or object ...
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:125