clang  10.0.0git
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  if (const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"))
539  return TempPCHFile(TmpFile);
540 
542  // Using a version of createTemporaryFile with a file descriptor guarantees
543  // that we would never get a race condition in a multi-threaded setting
544  // (i.e., multiple threads getting the same temporary path).
545  int FD;
546  auto EC = llvm::sys::fs::createTemporaryFile("preamble", "pch", FD, File);
547  if (EC)
548  return EC;
549  // We only needed to make sure the file exists, close the file right away.
550  llvm::sys::Process::SafelyCloseFileDescriptor(FD);
551  return TempPCHFile(std::move(File).str());
552 }
553 
554 PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
555  : FilePath(std::move(FilePath)) {
556  TemporaryFiles::getInstance().addFile(*this->FilePath);
557 }
558 
559 PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
560  FilePath = std::move(Other.FilePath);
561  Other.FilePath = None;
562 }
563 
564 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
565 operator=(TempPCHFile &&Other) {
566  RemoveFileIfPresent();
567 
568  FilePath = std::move(Other.FilePath);
569  Other.FilePath = None;
570  return *this;
571 }
572 
573 PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
574 
575 void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
576  if (FilePath) {
577  TemporaryFiles::getInstance().removeFile(*FilePath);
578  FilePath = None;
579  }
580 }
581 
582 llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
583  assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
584  return *FilePath;
585 }
586 
587 PrecompiledPreamble::PCHStorage::PCHStorage(TempPCHFile File)
588  : StorageKind(Kind::TempFile) {
589  new (&asFile()) TempPCHFile(std::move(File));
590 }
591 
592 PrecompiledPreamble::PCHStorage::PCHStorage(InMemoryPreamble Memory)
593  : StorageKind(Kind::InMemory) {
594  new (&asMemory()) InMemoryPreamble(std::move(Memory));
595 }
596 
597 PrecompiledPreamble::PCHStorage::PCHStorage(PCHStorage &&Other) : PCHStorage() {
598  *this = std::move(Other);
599 }
600 
601 PrecompiledPreamble::PCHStorage &PrecompiledPreamble::PCHStorage::
602 operator=(PCHStorage &&Other) {
603  destroy();
604 
605  StorageKind = Other.StorageKind;
606  switch (StorageKind) {
607  case Kind::Empty:
608  // do nothing;
609  break;
610  case Kind::TempFile:
611  new (&asFile()) TempPCHFile(std::move(Other.asFile()));
612  break;
613  case Kind::InMemory:
614  new (&asMemory()) InMemoryPreamble(std::move(Other.asMemory()));
615  break;
616  }
617 
618  Other.setEmpty();
619  return *this;
620 }
621 
622 PrecompiledPreamble::PCHStorage::~PCHStorage() { destroy(); }
623 
624 PrecompiledPreamble::PCHStorage::Kind
626  return StorageKind;
627 }
628 
629 PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::PCHStorage::asFile() {
630  assert(getKind() == Kind::TempFile);
631  return *reinterpret_cast<TempPCHFile *>(Storage.buffer);
632 }
633 
634 const PrecompiledPreamble::TempPCHFile &
635 PrecompiledPreamble::PCHStorage::asFile() const {
636  return const_cast<PCHStorage *>(this)->asFile();
637 }
638 
639 PrecompiledPreamble::InMemoryPreamble &
640 PrecompiledPreamble::PCHStorage::asMemory() {
641  assert(getKind() == Kind::InMemory);
642  return *reinterpret_cast<InMemoryPreamble *>(Storage.buffer);
643 }
644 
645 const PrecompiledPreamble::InMemoryPreamble &
646 PrecompiledPreamble::PCHStorage::asMemory() const {
647  return const_cast<PCHStorage *>(this)->asMemory();
648 }
649 
650 void PrecompiledPreamble::PCHStorage::destroy() {
651  switch (StorageKind) {
652  case Kind::Empty:
653  return;
654  case Kind::TempFile:
655  asFile().~TempPCHFile();
656  return;
657  case Kind::InMemory:
658  asMemory().~InMemoryPreamble();
659  return;
660  }
661 }
662 
663 void PrecompiledPreamble::PCHStorage::setEmpty() {
664  destroy();
665  StorageKind = Kind::Empty;
666 }
667 
668 PrecompiledPreamble::PreambleFileHash
669 PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
670  time_t ModTime) {
671  PreambleFileHash Result;
672  Result.Size = Size;
673  Result.ModTime = ModTime;
674  Result.MD5 = {};
675  return Result;
676 }
677 
678 PrecompiledPreamble::PreambleFileHash
679 PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
680  const llvm::MemoryBuffer *Buffer) {
681  PreambleFileHash Result;
682  Result.Size = Buffer->getBufferSize();
683  Result.ModTime = 0;
684 
685  llvm::MD5 MD5Ctx;
686  MD5Ctx.update(Buffer->getBuffer().data());
687  MD5Ctx.final(Result.MD5);
688 
689  return Result;
690 }
691 
692 void PrecompiledPreamble::configurePreamble(
695  llvm::MemoryBuffer *MainFileBuffer) const {
696  assert(VFS);
697 
698  auto &PreprocessorOpts = CI.getPreprocessorOpts();
699 
700  // Remap main file to point to MainFileBuffer.
701  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
702  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
703 
704  // Configure ImpicitPCHInclude.
705  PreprocessorOpts.PrecompiledPreambleBytes.first = Bounds.Size;
706  PreprocessorOpts.PrecompiledPreambleBytes.second =
708  PreprocessorOpts.DisablePCHValidation = true;
709 
710  setupPreambleStorage(Storage, PreprocessorOpts, VFS);
711 }
712 
713 void PrecompiledPreamble::setupPreambleStorage(
714  const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
716  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
717  const TempPCHFile &PCHFile = Storage.asFile();
718  PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
719 
720  // Make sure we can access the PCH file even if we're using a VFS
722  llvm::vfs::getRealFileSystem();
723  auto PCHPath = PCHFile.getFilePath();
724  if (VFS == RealFS || VFS->exists(PCHPath))
725  return;
726  auto Buf = RealFS->getBufferForFile(PCHPath);
727  if (!Buf) {
728  // We can't read the file even from RealFS, this is clearly an error,
729  // but we'll just leave the current VFS as is and let clang's code
730  // figure out what to do with missing PCH.
731  return;
732  }
733 
734  // We have a slight inconsistency here -- we're using the VFS to
735  // read files, but the PCH was generated in the real file system.
736  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
737  } else {
738  assert(Storage.getKind() == PCHStorage::Kind::InMemory);
739  // For in-memory preamble, we have to provide a VFS overlay that makes it
740  // accessible.
741  StringRef PCHPath = getInMemoryPreamblePath();
742  PreprocessorOpts.ImplicitPCHInclude = PCHPath;
743 
744  auto Buf = llvm::MemoryBuffer::getMemBuffer(Storage.asMemory().Data);
745  VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
746  }
747 }
748 
753 std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
754  return nullptr;
755 }
757 
758 static llvm::ManagedStatic<BuildPreambleErrorCategory> BuildPreambleErrCategory;
759 
761  return std::error_code(static_cast<int>(Error), *BuildPreambleErrCategory);
762 }
763 
764 const char *BuildPreambleErrorCategory::name() const noexcept {
765  return "build-preamble.error";
766 }
767 
768 std::string BuildPreambleErrorCategory::message(int condition) const {
769  switch (static_cast<BuildPreambleError>(condition)) {
771  return "Could not create temporary file for PCH";
773  return "CreateTargetInfo() return null";
775  return "BeginSourceFile() return an error";
777  return "Could not emit PCH";
779  return "Command line arguments must contain exactly one source file";
780  }
781  llvm_unreachable("unexpected BuildPreambleError");
782 }
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:76
The translation unit is a prefix to a translation unit, and is not complete.
Definition: LangOptions.h:418
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:168
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:2445
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:53
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()
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
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:1825
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: RewriteRule.cpp:82
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr< TargetOptions > &Opts)
Construct a target for the given options.
Definition: Targets.cpp:620
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.
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:412
Writes an AST file containing the contents of a translation unit.
Definition: ASTWriter.h:96
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:947
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:740
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:128