Coverage Report

Created: 2022-07-16 07:03

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Frontend/PrecompiledPreamble.cpp
Line
Count
Source (jump to first uncovered line)
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
13
#include "clang/Frontend/PrecompiledPreamble.h"
14
#include "clang/Basic/FileManager.h"
15
#include "clang/Basic/LangStandard.h"
16
#include "clang/Frontend/CompilerInstance.h"
17
#include "clang/Frontend/CompilerInvocation.h"
18
#include "clang/Frontend/FrontendActions.h"
19
#include "clang/Frontend/FrontendOptions.h"
20
#include "clang/Lex/HeaderSearch.h"
21
#include "clang/Lex/Lexer.h"
22
#include "clang/Lex/Preprocessor.h"
23
#include "clang/Lex/PreprocessorOptions.h"
24
#include "clang/Serialization/ASTWriter.h"
25
#include "llvm/ADT/SmallString.h"
26
#include "llvm/ADT/StringSet.h"
27
#include "llvm/ADT/iterator_range.h"
28
#include "llvm/Config/llvm-config.h"
29
#include "llvm/Support/CrashRecoveryContext.h"
30
#include "llvm/Support/FileSystem.h"
31
#include "llvm/Support/Path.h"
32
#include "llvm/Support/Process.h"
33
#include "llvm/Support/VirtualFileSystem.h"
34
#include <limits>
35
#include <mutex>
36
#include <utility>
37
38
using namespace clang;
39
40
namespace {
41
42
0
StringRef getInMemoryPreamblePath() {
43
0
#if defined(LLVM_ON_UNIX)
44
0
  return "/__clang_tmp/___clang_inmemory_preamble___";
45
#elif defined(_WIN32)
46
  return "C:\\__clang_tmp\\___clang_inmemory_preamble___";
47
#else
48
#warning "Unknown platform. Defaulting to UNIX-style paths for in-memory PCHs"
49
  return "/__clang_tmp/___clang_inmemory_preamble___";
50
#endif
51
0
}
52
53
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
54
createVFSOverlayForPreamblePCH(StringRef PCHFilename,
55
                               std::unique_ptr<llvm::MemoryBuffer> PCHBuffer,
56
13
                               IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
57
  // We want only the PCH file from the real filesystem to be available,
58
  // so we create an in-memory VFS with just that and overlay it on top.
59
13
  IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> PCHFS(
60
13
      new llvm::vfs::InMemoryFileSystem());
61
13
  PCHFS->addFile(PCHFilename, 0, std::move(PCHBuffer));
62
13
  IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> Overlay(
63
13
      new llvm::vfs::OverlayFileSystem(VFS));
64
13
  Overlay->pushOverlay(PCHFS);
65
13
  return Overlay;
66
13
}
67
68
class PreambleDependencyCollector : public DependencyCollector {
69
public:
70
  // We want to collect all dependencies for correctness. Avoiding the real
71
  // system dependencies (e.g. stl from /usr/lib) would probably be a good idea,
72
  // but there is no way to distinguish between those and the ones that can be
73
  // spuriously added by '-isystem' (e.g. to suppress warnings from those
74
  // headers).
75
295
  bool needSystemDependencies() override { return true; }
76
};
77
78
// Collects files whose existence would invalidate the preamble.
79
// Collecting *all* of these would make validating it too slow though, so we
80
// just find all the candidates for 'file not found' diagnostics.
81
//
82
// A caveat that may be significant for generated files: we'll omit files under
83
// search path entries whose roots don't exist when the preamble is built.
84
// These are pruned by InitHeaderSearch and so we don't see the search path.
85
// It would be nice to include them but we don't want to duplicate all the rest
86
// of the InitHeaderSearch logic to reconstruct them.
87
class MissingFileCollector : public PPCallbacks {
88
  llvm::StringSet<> &Out;
89
  const HeaderSearch &Search;
90
  const SourceManager &SM;
91
92
public:
93
  MissingFileCollector(llvm::StringSet<> &Out, const HeaderSearch &Search,
94
                       const SourceManager &SM)
95
91
      : Out(Out), Search(Search), SM(SM) {}
96
97
  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
98
                          StringRef FileName, bool IsAngled,
99
                          CharSourceRange FilenameRange,
100
                          Optional<FileEntryRef> File, StringRef SearchPath,
101
                          StringRef RelativePath, const Module *Imported,
102
96
                          SrcMgr::CharacteristicKind FileType) override {
103
    // File is None if it wasn't found.
104
    // (We have some false negatives if PP recovered e.g. <foo> -> "foo")
105
96
    if (File)
106
95
      return;
107
108
    // If it's a rare absolute include, we know the full path already.
109
1
    if (llvm::sys::path::is_absolute(FileName)) {
110
0
      Out.insert(FileName);
111
0
      return;
112
0
    }
113
114
    // Reconstruct the filenames that would satisfy this directive...
115
1
    llvm::SmallString<256> Buf;
116
3
    auto NotFoundRelativeTo = [&](const DirectoryEntry *DE) {
117
3
      Buf = DE->getName();
118
3
      llvm::sys::path::append(Buf, FileName);
119
3
      llvm::sys::path::remove_dots(Buf, /*remove_dot_dot=*/true);
120
3
      Out.insert(Buf);
121
3
    };
122
    // ...relative to the including file.
123
1
    if (!IsAngled) {
124
1
      if (const FileEntry *IncludingFile =
125
1
              SM.getFileEntryForID(SM.getFileID(IncludeTok.getLocation())))
126
1
        if (IncludingFile->getDir())
127
1
          NotFoundRelativeTo(IncludingFile->getDir());
128
1
    }
129
    // ...relative to the search paths.
130
1
    for (const auto &Dir : llvm::make_range(
131
1
             IsAngled ? 
Search.angled_dir_begin()0
: Search.search_dir_begin(),
132
3
             Search.search_dir_end())) {
133
      // No support for frameworks or header maps yet.
134
3
      if (Dir.isNormalDir())
135
2
        NotFoundRelativeTo(Dir.getDir());
136
3
    }
137
1
  }
138
};
139
140
/// Keeps a track of files to be deleted in destructor.
141
class TemporaryFiles {
142
public:
143
  // A static instance to be used by all clients.
144
  static TemporaryFiles &getInstance();
145
146
private:
147
  // Disallow constructing the class directly.
148
84
  TemporaryFiles() = default;
149
  // Disallow copy.
150
  TemporaryFiles(const TemporaryFiles &) = delete;
151
152
public:
153
  ~TemporaryFiles();
154
155
  /// Adds \p File to a set of tracked files.
156
  void addFile(StringRef File);
157
158
  /// Remove \p File from disk and from the set of tracked files.
159
  void removeFile(StringRef File);
160
161
private:
162
  std::mutex Mutex;
163
  llvm::StringSet<> Files;
164
};
165
166
181
TemporaryFiles &TemporaryFiles::getInstance() {
167
181
  static TemporaryFiles Instance;
168
181
  return Instance;
169
181
}
170
171
84
TemporaryFiles::~TemporaryFiles() {
172
84
  std::lock_guard<std::mutex> Guard(Mutex);
173
84
  for (const auto &File : Files)
174
1
    llvm::sys::fs::remove(File.getKey());
175
84
}
176
177
91
void TemporaryFiles::addFile(StringRef File) {
178
91
  std::lock_guard<std::mutex> Guard(Mutex);
179
91
  auto IsInserted = Files.insert(File).second;
180
91
  (void)IsInserted;
181
91
  assert(IsInserted && "File has already been added");
182
91
}
183
184
90
void TemporaryFiles::removeFile(StringRef File) {
185
90
  std::lock_guard<std::mutex> Guard(Mutex);
186
90
  auto WasPresent = Files.erase(File);
187
90
  (void)WasPresent;
188
90
  assert(WasPresent && "File was not tracked");
189
0
  llvm::sys::fs::remove(File);
190
90
}
191
192
// A temp file that would be deleted on destructor call. If destructor is not
193
// called for any reason, the file will be deleted at static objects'
194
// destruction.
195
// An assertion will fire if two TempPCHFiles are created with the same name,
196
// so it's not intended to be used outside preamble-handling.
197
class TempPCHFile {
198
public:
199
  // A main method used to construct TempPCHFile.
200
91
  static std::unique_ptr<TempPCHFile> create() {
201
    // FIXME: This is a hack so that we can override the preamble file during
202
    // crash-recovery testing, which is the only case where the preamble files
203
    // are not necessarily cleaned up.
204
91
    if (const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"))
205
2
      return std::unique_ptr<TempPCHFile>(new TempPCHFile(TmpFile));
206
207
89
    llvm::SmallString<64> File;
208
    // Using a version of createTemporaryFile with a file descriptor guarantees
209
    // that we would never get a race condition in a multi-threaded setting
210
    // (i.e., multiple threads getting the same temporary path).
211
89
    int FD;
212
89
    if (auto EC =
213
89
            llvm::sys::fs::createTemporaryFile("preamble", "pch", FD, File))
214
0
      return nullptr;
215
    // We only needed to make sure the file exists, close the file right away.
216
89
    llvm::sys::Process::SafelyCloseFileDescriptor(FD);
217
89
    return std::unique_ptr<TempPCHFile>(new TempPCHFile(File.str().str()));
218
89
  }
219
220
  TempPCHFile &operator=(const TempPCHFile &) = delete;
221
  TempPCHFile(const TempPCHFile &) = delete;
222
90
  ~TempPCHFile() { TemporaryFiles::getInstance().removeFile(FilePath); };
223
224
  /// A path where temporary file is stored.
225
429
  llvm::StringRef getFilePath() const { return FilePath; };
226
227
private:
228
91
  TempPCHFile(std::string FilePath) : FilePath(std::move(FilePath)) {
229
91
    TemporaryFiles::getInstance().addFile(this->FilePath);
230
91
  }
231
232
  std::string FilePath;
233
};
234
235
class PrecompilePreambleAction : public ASTFrontendAction {
236
public:
237
  PrecompilePreambleAction(std::shared_ptr<PCHBuffer> Buffer, bool WritePCHFile,
238
                           PreambleCallbacks &Callbacks)
239
      : Buffer(std::move(Buffer)), WritePCHFile(WritePCHFile),
240
91
        Callbacks(Callbacks) {}
241
242
  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
243
                                                 StringRef InFile) override;
244
245
182
  bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
246
247
91
  void setEmittedPreamblePCH(ASTWriter &Writer) {
248
91
    if (FileOS) {
249
91
      *FileOS << Buffer->Data;
250
      // Make sure it hits disk now.
251
91
      FileOS.reset();
252
91
    }
253
254
91
    this->HasEmittedPreamblePCH = true;
255
91
    Callbacks.AfterPCHEmitted(Writer);
256
91
  }
257
258
91
  bool BeginSourceFileAction(CompilerInstance &CI) override {
259
91
    assert(CI.getLangOpts().CompilingPCH);
260
0
    return ASTFrontendAction::BeginSourceFileAction(CI);
261
91
  }
262
263
91
  bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
264
91
  bool hasCodeCompletionSupport() const override { return false; }
265
0
  bool hasASTFileSupport() const override { return false; }
266
182
  TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
267
268
private:
269
  friend class PrecompilePreambleConsumer;
270
271
  bool HasEmittedPreamblePCH = false;
272
  std::shared_ptr<PCHBuffer> Buffer;
273
  bool WritePCHFile; // otherwise the PCH is written into the PCHBuffer only.
274
  std::unique_ptr<llvm::raw_pwrite_stream> FileOS; // null if in-memory
275
  PreambleCallbacks &Callbacks;
276
};
277
278
class PrecompilePreambleConsumer : public PCHGenerator {
279
public:
280
  PrecompilePreambleConsumer(PrecompilePreambleAction &Action,
281
                             const Preprocessor &PP,
282
                             InMemoryModuleCache &ModuleCache,
283
                             StringRef isysroot,
284
                             std::shared_ptr<PCHBuffer> Buffer)
285
      : PCHGenerator(PP, ModuleCache, "", isysroot, std::move(Buffer),
286
                     ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
287
                     /*AllowASTWithErrors=*/true),
288
91
        Action(Action) {}
289
290
87
  bool HandleTopLevelDecl(DeclGroupRef DG) override {
291
87
    Action.Callbacks.HandleTopLevelDecl(DG);
292
87
    return true;
293
87
  }
294
295
91
  void HandleTranslationUnit(ASTContext &Ctx) override {
296
91
    PCHGenerator::HandleTranslationUnit(Ctx);
297
91
    if (!hasEmittedPCH())
298
0
      return;
299
91
    Action.setEmittedPreamblePCH(getWriter());
300
91
  }
301
302
1
  bool shouldSkipFunctionBody(Decl *D) override {
303
1
    return Action.Callbacks.shouldSkipFunctionBody(D);
304
1
  }
305
306
private:
307
  PrecompilePreambleAction &Action;
308
};
309
310
std::unique_ptr<ASTConsumer>
311
PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
312
91
                                            StringRef InFile) {
313
91
  std::string Sysroot;
314
91
  if (!GeneratePCHAction::ComputeASTConsumerArguments(CI, Sysroot))
315
0
    return nullptr;
316
317
91
  if (WritePCHFile) {
318
91
    std::string OutputFile; // unused
319
91
    FileOS = GeneratePCHAction::CreateOutputFile(CI, InFile, OutputFile);
320
91
    if (!FileOS)
321
0
      return nullptr;
322
91
  }
323
324
91
  if (!CI.getFrontendOpts().RelocatablePCH)
325
91
    Sysroot.clear();
326
327
91
  return std::make_unique<PrecompilePreambleConsumer>(
328
91
      *this, CI.getPreprocessor(), CI.getModuleCache(), Sysroot, Buffer);
329
91
}
330
331
467
template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
332
467
  if (!Val)
333
2
    return false;
334
465
  Output = std::move(*Val);
335
465
  return true;
336
467
}
337
338
} // namespace
339
340
PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts,
341
                                            const llvm::MemoryBufferRef &Buffer,
342
520
                                            unsigned MaxLines) {
343
520
  return Lexer::ComputePreamble(Buffer.getBuffer(), LangOpts, MaxLines);
344
520
}
345
346
class PrecompiledPreamble::PCHStorage {
347
public:
348
91
  static std::unique_ptr<PCHStorage> file(std::unique_ptr<TempPCHFile> File) {
349
91
    assert(File);
350
0
    std::unique_ptr<PCHStorage> S(new PCHStorage());
351
91
    S->File = std::move(File);
352
91
    return S;
353
91
  }
354
0
  static std::unique_ptr<PCHStorage> inMemory(std::shared_ptr<PCHBuffer> Buf) {
355
0
    std::unique_ptr<PCHStorage> S(new PCHStorage());
356
0
    S->Memory = std::move(Buf);
357
0
    return S;
358
0
  }
359
360
  enum class Kind { InMemory, TempFile };
361
858
  Kind getKind() const {
362
858
    if (Memory)
363
0
      return Kind::InMemory;
364
858
    if (File)
365
858
      return Kind::TempFile;
366
0
    llvm_unreachable("Neither Memory nor File?");
367
0
  }
368
429
  llvm::StringRef filePath() const {
369
429
    assert(getKind() == Kind::TempFile);
370
0
    return File->getFilePath();
371
429
  }
372
0
  llvm::StringRef memoryContents() const {
373
0
    assert(getKind() == Kind::InMemory);
374
0
    return StringRef(Memory->Data.data(), Memory->Data.size());
375
0
  }
376
377
  // Shrink in-memory buffers to fit.
378
  // This incurs a copy, but preambles tend to be long-lived.
379
  // Only safe to call once nothing can alias the buffer.
380
91
  void shrink() {
381
91
    if (!Memory)
382
91
      return;
383
0
    Memory->Data = decltype(Memory->Data)(Memory->Data);
384
0
  }
385
386
private:
387
91
  PCHStorage() = default;
388
  PCHStorage(const PCHStorage &) = delete;
389
  PCHStorage &operator=(const PCHStorage &) = delete;
390
391
  std::shared_ptr<PCHBuffer> Memory;
392
  std::unique_ptr<TempPCHFile> File;
393
};
394
395
272
PrecompiledPreamble::~PrecompiledPreamble() = default;
396
182
PrecompiledPreamble::PrecompiledPreamble(PrecompiledPreamble &&) = default;
397
PrecompiledPreamble &
398
0
PrecompiledPreamble::operator=(PrecompiledPreamble &&) = default;
399
400
llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
401
    const CompilerInvocation &Invocation,
402
    const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
403
    DiagnosticsEngine &Diagnostics,
404
    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
405
    std::shared_ptr<PCHContainerOperations> PCHContainerOps, bool StoreInMemory,
406
91
    PreambleCallbacks &Callbacks) {
407
91
  assert(VFS && "VFS is null");
408
409
0
  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
410
91
  FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
411
91
  PreprocessorOptions &PreprocessorOpts =
412
91
      PreambleInvocation->getPreprocessorOpts();
413
414
91
  std::shared_ptr<PCHBuffer> Buffer = std::make_shared<PCHBuffer>();
415
91
  std::unique_ptr<PCHStorage> Storage;
416
91
  if (StoreInMemory) {
417
0
    Storage = PCHStorage::inMemory(Buffer);
418
91
  } else {
419
    // Create a temporary file for the precompiled preamble. In rare
420
    // circumstances, this can fail.
421
91
    std::unique_ptr<TempPCHFile> PreamblePCHFile = TempPCHFile::create();
422
91
    if (!PreamblePCHFile)
423
0
      return BuildPreambleError::CouldntCreateTempFile;
424
91
    Storage = PCHStorage::file(std::move(PreamblePCHFile));
425
91
  }
426
427
  // Save the preamble text for later; we'll need to compare against it for
428
  // subsequent reparses.
429
91
  std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
430
91
                                  MainFileBuffer->getBufferStart() +
431
91
                                      Bounds.Size);
432
91
  bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
433
434
  // Tell the compiler invocation to generate a temporary precompiled header.
435
91
  FrontendOpts.ProgramAction = frontend::GeneratePCH;
436
91
  FrontendOpts.OutputFile = std::string(
437
91
      StoreInMemory ? 
getInMemoryPreamblePath()0
: Storage->filePath());
438
91
  PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
439
91
  PreprocessorOpts.PrecompiledPreambleBytes.second = false;
440
  // Inform preprocessor to record conditional stack when building the preamble.
441
91
  PreprocessorOpts.GeneratePreamble = true;
442
443
  // Create the compiler instance to use for building the precompiled preamble.
444
91
  std::unique_ptr<CompilerInstance> Clang(
445
91
      new CompilerInstance(std::move(PCHContainerOps)));
446
447
  // Recover resources if we crash before exiting this method.
448
91
  llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
449
91
      Clang.get());
450
451
91
  Clang->setInvocation(std::move(PreambleInvocation));
452
91
  Clang->setDiagnostics(&Diagnostics);
453
454
  // Create the target instance.
455
91
  if (!Clang->createTarget())
456
0
    return BuildPreambleError::CouldntCreateTargetInfo;
457
458
91
  if (Clang->getFrontendOpts().Inputs.size() != 1 ||
459
91
      Clang->getFrontendOpts().Inputs[0].getKind().getFormat() !=
460
91
          InputKind::Source ||
461
91
      Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() ==
462
91
          Language::LLVM_IR) {
463
0
    return BuildPreambleError::BadInputs;
464
0
  }
465
466
  // Clear out old caches and data.
467
91
  Diagnostics.Reset();
468
91
  ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
469
470
91
  VFS =
471
91
      createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
472
473
  // Create a file manager object to provide access to and cache the filesystem.
474
91
  Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
475
476
  // Create the source manager.
477
91
  Clang->setSourceManager(
478
91
      new SourceManager(Diagnostics, Clang->getFileManager()));
479
480
91
  auto PreambleDepCollector = std::make_shared<PreambleDependencyCollector>();
481
91
  Clang->addDependencyCollector(PreambleDepCollector);
482
483
91
  Clang->getLangOpts().CompilingPCH = true;
484
485
  // Remap the main source file to the preamble buffer.
486
91
  StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
487
91
  auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
488
91
      MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
489
91
  if (PreprocessorOpts.RetainRemappedFileBuffers) {
490
    // MainFileBuffer will be deleted by unique_ptr after leaving the method.
491
91
    PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
492
91
  } else {
493
    // In that case, remapped buffer will be deleted by CompilerInstance on
494
    // BeginSourceFile, so we call release() to avoid double deletion.
495
0
    PreprocessorOpts.addRemappedFile(MainFilePath,
496
0
                                     PreambleInputBuffer.release());
497
0
  }
498
499
91
  auto Act = std::make_unique<PrecompilePreambleAction>(
500
91
      std::move(Buffer),
501
91
      /*WritePCHFile=*/Storage->getKind() == PCHStorage::Kind::TempFile,
502
91
      Callbacks);
503
91
  if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
504
0
    return BuildPreambleError::BeginSourceFileFailed;
505
506
  // Performed after BeginSourceFile to ensure Clang->Preprocessor can be
507
  // referenced in the callback.
508
91
  Callbacks.BeforeExecute(*Clang);
509
510
91
  std::unique_ptr<PPCallbacks> DelegatedPPCallbacks =
511
91
      Callbacks.createPPCallbacks();
512
91
  if (DelegatedPPCallbacks)
513
91
    Clang->getPreprocessor().addPPCallbacks(std::move(DelegatedPPCallbacks));
514
91
  if (auto CommentHandler = Callbacks.getCommentHandler())
515
0
    Clang->getPreprocessor().addCommentHandler(CommentHandler);
516
91
  llvm::StringSet<> MissingFiles;
517
91
  Clang->getPreprocessor().addPPCallbacks(
518
91
      std::make_unique<MissingFileCollector>(
519
91
          MissingFiles, Clang->getPreprocessor().getHeaderSearchInfo(),
520
91
          Clang->getSourceManager()));
521
522
91
  if (llvm::Error Err = Act->Execute())
523
0
    return errorToErrorCode(std::move(Err));
524
525
  // Run the callbacks.
526
91
  Callbacks.AfterExecute(*Clang);
527
528
91
  Act->EndSourceFile();
529
530
91
  if (!Act->hasEmittedPreamblePCH())
531
0
    return BuildPreambleError::CouldntEmitPCH;
532
91
  Act.reset(); // Frees the PCH buffer, unless Storage keeps it in memory.
533
534
  // Keep track of all of the files that the source manager knows about,
535
  // so we can verify whether they have changed or not.
536
91
  llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
537
538
91
  SourceManager &SourceMgr = Clang->getSourceManager();
539
250
  for (auto &Filename : PreambleDepCollector->getDependencies()) {
540
250
    auto FileOrErr = Clang->getFileManager().getFile(Filename);
541
250
    if (!FileOrErr ||
542
250
        
*FileOrErr == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())249
)
543
92
      continue;
544
158
    auto File = *FileOrErr;
545
158
    if (time_t ModTime = File->getModificationTime()) {
546
148
      FilesInPreamble[File->getName()] =
547
148
          PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
548
148
                                                               ModTime);
549
148
    } else {
550
10
      llvm::MemoryBufferRef Buffer =
551
10
          SourceMgr.getMemoryBufferForFileOrFake(File);
552
10
      FilesInPreamble[File->getName()] =
553
10
          PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
554
10
    }
555
158
  }
556
557
  // Shrinking the storage requires extra temporary memory.
558
  // Destroying clang first reduces peak memory usage.
559
91
  CICleanup.unregister();
560
91
  Clang.reset();
561
91
  Storage->shrink();
562
91
  return PrecompiledPreamble(
563
91
      std::move(Storage), std::move(PreambleBytes), PreambleEndsAtStartOfLine,
564
91
      std::move(FilesInPreamble), std::move(MissingFiles));
565
91
}
566
567
539
PreambleBounds PrecompiledPreamble::getBounds() const {
568
539
  return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
569
539
}
570
571
0
std::size_t PrecompiledPreamble::getSize() const {
572
0
  switch (Storage->getKind()) {
573
0
  case PCHStorage::Kind::InMemory:
574
0
    return Storage->memoryContents().size();
575
0
  case PCHStorage::Kind::TempFile: {
576
0
    uint64_t Result;
577
0
    if (llvm::sys::fs::file_size(Storage->filePath(), Result))
578
0
      return 0;
579
580
0
    assert(Result <= std::numeric_limits<std::size_t>::max() &&
581
0
           "file size did not fit into size_t");
582
0
    return Result;
583
0
  }
584
0
  }
585
0
  llvm_unreachable("Unhandled storage kind");
586
0
}
587
588
bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation,
589
                                   const llvm::MemoryBufferRef &MainFileBuffer,
590
                                   PreambleBounds Bounds,
591
257
                                   llvm::vfs::FileSystem &VFS) const {
592
593
257
  assert(
594
257
      Bounds.Size <= MainFileBuffer.getBufferSize() &&
595
257
      "Buffer is too large. Bounds were calculated from a different buffer?");
596
597
0
  auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
598
257
  PreprocessorOptions &PreprocessorOpts =
599
257
      PreambleInvocation->getPreprocessorOpts();
600
601
  // We've previously computed a preamble. Check whether we have the same
602
  // preamble now that we did before, and that there's enough space in
603
  // the main-file buffer within the precompiled preamble to fit the
604
  // new main file.
605
257
  if (PreambleBytes.size() != Bounds.Size ||
606
257
      
PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine251
||
607
257
      !std::equal(PreambleBytes.begin(), PreambleBytes.end(),
608
251
                  MainFileBuffer.getBuffer().begin()))
609
6
    return false;
610
  // The preamble has not changed. We may be able to re-use the precompiled
611
  // preamble.
612
613
  // Check that none of the files used by the preamble have changed.
614
  // First, make a record of those files that have been overridden via
615
  // remapping or unsaved_files.
616
251
  std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
617
251
  llvm::StringSet<> OverriddenAbsPaths; // Either by buffers or files.
618
251
  for (const auto &R : PreprocessorOpts.RemappedFiles) {
619
0
    llvm::vfs::Status Status;
620
0
    if (!moveOnNoError(VFS.status(R.second), Status)) {
621
      // If we can't stat the file we're remapping to, assume that something
622
      // horrible happened.
623
0
      return false;
624
0
    }
625
    // If a mapped file was previously missing, then it has changed.
626
0
    llvm::SmallString<128> MappedPath(R.first);
627
0
    if (!VFS.makeAbsolute(MappedPath))
628
0
      OverriddenAbsPaths.insert(MappedPath);
629
630
0
    OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
631
0
        Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
632
0
  }
633
634
  // OverridenFileBuffers tracks only the files not found in VFS.
635
251
  llvm::StringMap<PreambleFileHash> OverridenFileBuffers;
636
251
  for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
637
6
    const PrecompiledPreamble::PreambleFileHash PreambleHash =
638
6
        PreambleFileHash::createForMemoryBuffer(RB.second->getMemBufferRef());
639
6
    llvm::vfs::Status Status;
640
6
    if (moveOnNoError(VFS.status(RB.first), Status))
641
4
      OverriddenFiles[Status.getUniqueID()] = PreambleHash;
642
2
    else
643
2
      OverridenFileBuffers[RB.first] = PreambleHash;
644
645
6
    llvm::SmallString<128> MappedPath(RB.first);
646
6
    if (!VFS.makeAbsolute(MappedPath))
647
6
      OverriddenAbsPaths.insert(MappedPath);
648
6
  }
649
650
  // Check whether anything has changed.
651
463
  for (const auto &F : FilesInPreamble) {
652
463
    auto OverridenFileBuffer = OverridenFileBuffers.find(F.first());
653
463
    if (OverridenFileBuffer != OverridenFileBuffers.end()) {
654
      // The file's buffer was remapped and the file was not found in VFS.
655
      // Check whether it matches up with the previous mapping.
656
2
      if (OverridenFileBuffer->second != F.second)
657
0
        return false;
658
2
      continue;
659
2
    }
660
661
461
    llvm::vfs::Status Status;
662
461
    if (!moveOnNoError(VFS.status(F.first()), Status)) {
663
      // If the file's buffer is not remapped and we can't stat it,
664
      // assume that something horrible happened.
665
0
      return false;
666
0
    }
667
668
461
    std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
669
461
        OverriddenFiles.find(Status.getUniqueID());
670
461
    if (Overridden != OverriddenFiles.end()) {
671
      // This file was remapped; check whether the newly-mapped file
672
      // matches up with the previous mapping.
673
4
      if (Overridden->second != F.second)
674
2
        return false;
675
2
      continue;
676
4
    }
677
678
    // Neither the file's buffer nor the file itself was remapped;
679
    // check whether it has changed on disk.
680
457
    if (Status.getSize() != uint64_t(F.second.Size) ||
681
457
        llvm::sys::toTimeT(Status.getLastModificationTime()) !=
682
455
            F.second.ModTime)
683
2
      return false;
684
457
  }
685
247
  for (const auto &F : MissingFiles) {
686
    // A missing file may be "provided" by an override buffer or file.
687
12
    if (OverriddenAbsPaths.count(F.getKey()))
688
0
      return false;
689
    // If a file previously recorded as missing exists as a regular file, then
690
    // consider the preamble out-of-date.
691
12
    if (auto Status = VFS.status(F.getKey())) {
692
0
      if (Status->isRegularFile())
693
0
        return false;
694
0
    }
695
12
  }
696
247
  return true;
697
247
}
698
699
void PrecompiledPreamble::AddImplicitPreamble(
700
    CompilerInvocation &CI, IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
701
338
    llvm::MemoryBuffer *MainFileBuffer) const {
702
338
  PreambleBounds Bounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
703
338
  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
704
338
}
705
706
void PrecompiledPreamble::OverridePreamble(
707
    CompilerInvocation &CI, IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
708
0
    llvm::MemoryBuffer *MainFileBuffer) const {
709
0
  auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), *MainFileBuffer, 0);
710
0
  configurePreamble(Bounds, CI, VFS, MainFileBuffer);
711
0
}
712
713
PrecompiledPreamble::PrecompiledPreamble(
714
    std::unique_ptr<PCHStorage> Storage, std::vector<char> PreambleBytes,
715
    bool PreambleEndsAtStartOfLine,
716
    llvm::StringMap<PreambleFileHash> FilesInPreamble,
717
    llvm::StringSet<> MissingFiles)
718
    : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
719
      MissingFiles(std::move(MissingFiles)),
720
      PreambleBytes(std::move(PreambleBytes)),
721
91
      PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
722
91
  assert(this->Storage != nullptr);
723
91
}
724
725
PrecompiledPreamble::PreambleFileHash
726
PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
727
148
                                                     time_t ModTime) {
728
148
  PreambleFileHash Result;
729
148
  Result.Size = Size;
730
148
  Result.ModTime = ModTime;
731
148
  Result.MD5 = {};
732
148
  return Result;
733
148
}
734
735
PrecompiledPreamble::PreambleFileHash
736
PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
737
16
    const llvm::MemoryBufferRef &Buffer) {
738
16
  PreambleFileHash Result;
739
16
  Result.Size = Buffer.getBufferSize();
740
16
  Result.ModTime = 0;
741
742
16
  llvm::MD5 MD5Ctx;
743
16
  MD5Ctx.update(Buffer.getBuffer().data());
744
16
  MD5Ctx.final(Result.MD5);
745
746
16
  return Result;
747
16
}
748
749
void PrecompiledPreamble::configurePreamble(
750
    PreambleBounds Bounds, CompilerInvocation &CI,
751
    IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS,
752
338
    llvm::MemoryBuffer *MainFileBuffer) const {
753
338
  assert(VFS);
754
755
0
  auto &PreprocessorOpts = CI.getPreprocessorOpts();
756
757
  // Remap main file to point to MainFileBuffer.
758
338
  auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
759
338
  PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
760
761
  // Configure ImpicitPCHInclude.
762
338
  PreprocessorOpts.PrecompiledPreambleBytes.first = Bounds.Size;
763
338
  PreprocessorOpts.PrecompiledPreambleBytes.second =
764
338
      Bounds.PreambleEndsAtStartOfLine;
765
338
  PreprocessorOpts.DisablePCHOrModuleValidation =
766
338
      DisableValidationForModuleKind::PCH;
767
768
  // Don't bother generating the long version of the predefines buffer.
769
  // The preamble is going to overwrite it anyway.
770
338
  PreprocessorOpts.UsePredefines = false;
771
772
338
  setupPreambleStorage(*Storage, PreprocessorOpts, VFS);
773
338
}
774
775
void PrecompiledPreamble::setupPreambleStorage(
776
    const PCHStorage &Storage, PreprocessorOptions &PreprocessorOpts,
777
338
    IntrusiveRefCntPtr<llvm::vfs::FileSystem> &VFS) {
778
338
  if (Storage.getKind() == PCHStorage::Kind::TempFile) {
779
338
    llvm::StringRef PCHPath = Storage.filePath();
780
338
    PreprocessorOpts.ImplicitPCHInclude = PCHPath.str();
781
782
    // Make sure we can access the PCH file even if we're using a VFS
783
338
    IntrusiveRefCntPtr<llvm::vfs::FileSystem> RealFS =
784
338
        llvm::vfs::getRealFileSystem();
785
338
    if (VFS == RealFS || 
VFS->exists(PCHPath)13
)
786
325
      return;
787
13
    auto Buf = RealFS->getBufferForFile(PCHPath);
788
13
    if (!Buf) {
789
      // We can't read the file even from RealFS, this is clearly an error,
790
      // but we'll just leave the current VFS as is and let clang's code
791
      // figure out what to do with missing PCH.
792
0
      return;
793
0
    }
794
795
    // We have a slight inconsistency here -- we're using the VFS to
796
    // read files, but the PCH was generated in the real file system.
797
13
    VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(*Buf), VFS);
798
13
  } else {
799
0
    assert(Storage.getKind() == PCHStorage::Kind::InMemory);
800
    // For in-memory preamble, we have to provide a VFS overlay that makes it
801
    // accessible.
802
0
    StringRef PCHPath = getInMemoryPreamblePath();
803
0
    PreprocessorOpts.ImplicitPCHInclude = std::string(PCHPath);
804
805
0
    auto Buf = llvm::MemoryBuffer::getMemBuffer(
806
0
        Storage.memoryContents(), PCHPath, /*RequiresNullTerminator=*/false);
807
0
    VFS = createVFSOverlayForPreamblePCH(PCHPath, std::move(Buf), VFS);
808
0
  }
809
338
}
810
811
91
void PreambleCallbacks::BeforeExecute(CompilerInstance &CI) {}
812
91
void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {}
813
0
void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {}
814
0
void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {}
815
0
std::unique_ptr<PPCallbacks> PreambleCallbacks::createPPCallbacks() {
816
0
  return nullptr;
817
0
}
818
91
CommentHandler *PreambleCallbacks::getCommentHandler() { return nullptr; }
819
820
static llvm::ManagedStatic<BuildPreambleErrorCategory> BuildPreambleErrCategory;
821
822
0
std::error_code clang::make_error_code(BuildPreambleError Error) {
823
0
  return std::error_code(static_cast<int>(Error), *BuildPreambleErrCategory);
824
0
}
825
826
0
const char *BuildPreambleErrorCategory::name() const noexcept {
827
0
  return "build-preamble.error";
828
0
}
829
830
0
std::string BuildPreambleErrorCategory::message(int condition) const {
831
0
  switch (static_cast<BuildPreambleError>(condition)) {
832
0
  case BuildPreambleError::CouldntCreateTempFile:
833
0
    return "Could not create temporary file for PCH";
834
0
  case BuildPreambleError::CouldntCreateTargetInfo:
835
0
    return "CreateTargetInfo() return null";
836
0
  case BuildPreambleError::BeginSourceFileFailed:
837
0
    return "BeginSourceFile() return an error";
838
0
  case BuildPreambleError::CouldntEmitPCH:
839
0
    return "Could not emit PCH";
840
0
  case BuildPreambleError::BadInputs:
841
0
    return "Command line arguments must contain exactly one source file";
842
0
  }
843
0
  llvm_unreachable("unexpected BuildPreambleError");
844
0
}