Skip to content

Commit e8e06ce

Browse files
committed
Make PCH's respect any VFS specified.
We want to be able to generate a PCH against one file-system path, and then re-use that PCH when the file-system path is different (but the sources are the same). We also do not know when generating the PCH what the destination file-system path will be, so what we want to be able to do is: - When generating a PCH map the original directory to some fake directory. You could imagine `D:/Foo` being mapped to `Z:/Foo` for instance. - Then when consuming a PCH, we want to be able to use a different mapping to map `Z:/Foo` to `D:/Some/Other/Machines/Foo` for instance. This will let us generate and share PCHs to speed up compile time for our users. To enable this we've made PCH generation respect any specified vfsoverlay, such that it will remap the paths in the PCH accordingly. We've also made `-verify-pch` respect the `-fvalidate-ast-input-files-content` option so that we can force verification of inputs.
1 parent 175aa86 commit e8e06ce

File tree

5 files changed

+62
-3
lines changed

5 files changed

+62
-3
lines changed

clang/lib/Frontend/FrontendActions.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,8 @@ void VerifyPCHAction::ExecuteAction() {
347347
DisableValidationForModuleKind::None,
348348
/*AllowASTWithCompilerErrors*/ false,
349349
/*AllowConfigurationMismatch*/ true,
350-
/*ValidateSystemInputs*/ true));
350+
/*ValidateSystemInputs*/ true,
351+
CI.getHeaderSearchOpts().ValidateASTInputFilesContent));
351352

352353
Reader->ReadAST(getCurrentFile(),
353354
Preamble ? serialization::MK_Preamble

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,13 +1115,13 @@ void ASTWriter::WriteBlockInfoBlock() {
11151115
}
11161116

11171117
/// Prepares a path for being written to an AST file by converting it
1118-
/// to an absolute path and removing nested './'s.
1118+
/// to an absolute path and removing nested './'s and '../'s.
11191119
///
11201120
/// \return \c true if the path was changed.
11211121
static bool cleanPathForOutput(FileManager &FileMgr,
11221122
SmallVectorImpl<char> &Path) {
11231123
bool Changed = FileMgr.makeAbsolutePath(Path);
1124-
return Changed | llvm::sys::path::remove_dots(Path);
1124+
return Changed | llvm::sys::path::remove_dots(Path, true);
11251125
}
11261126

11271127
/// Adjusts the given filename to only write out the portion of the
@@ -4772,6 +4772,21 @@ bool ASTWriter::PreparePathForOutput(SmallVectorImpl<char> &Path) {
47724772
Changed = true;
47734773
}
47744774

4775+
// If we are generating a normal PCH (EG. not a C++ module).
4776+
if (!WritingModule) {
4777+
// Use the vfs overlay if it exists to translate paths.
4778+
auto& FileSys = Context->getSourceManager().getFileManager().getVirtualFileSystem();
4779+
if (auto *RFS = dyn_cast<llvm::vfs::RedirectingFileSystem>(&FileSys)) {
4780+
if (auto Result = RFS->lookupPath(PathStr)) {
4781+
if (std::optional<StringRef> Redirect = Result->getExternalRedirect()) {
4782+
PathStr = *Redirect;
4783+
Path.assign(PathStr.data(), PathStr.data() + PathStr.size());
4784+
Changed = true;
4785+
}
4786+
}
4787+
}
4788+
}
4789+
47754790
return Changed;
47764791
}
47774792

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: echo 'int SomeFunc() { return 42; }' > %t.h
2+
// RUN: %clang_cc1 -Werror -fno-pch-timestamp -fvalidate-ast-input-files-content -emit-pch -o "%t.pch" %t.h
3+
4+
// Now change the source file, which should cause the verifier to fail with content mismatch.
5+
// RUN: echo 'int SomeFunc() { return 13; }' > %t.h
6+
// RUN: not %clang_cc1 -fno-pch-timestamp -fvalidate-ast-input-files-content -verify-pch %t.pch 2>&1 | FileCheck %s -DT=%t
7+
8+
// CHECK: fatal error: file '[[T]].h' has been modified since the precompiled header '[[T]].pch' was built: content changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
'version': 0,
3+
'roots': [
4+
{ 'name': 'FROM_DIR',
5+
'type': 'directory-remap',
6+
'external-contents': 'TO_DIR'
7+
}
8+
]
9+
}

clang/test/VFS/remap-to-fake.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t/From
3+
// RUN: mkdir -p %t/To
4+
// RUN: echo '#pragma once' > %t/From/B.h
5+
// RUN: echo 'int SomeFunc() { return 13; }' >> %t/From/B.h
6+
// RUN: echo '#pragma once' > %t/To/B.h
7+
// RUN: echo 'int SomeFunc() { return 13; }' >> %t/To/B.h
8+
// RUN: sed -e "s@FROM_DIR@%{/t:regex_replacement}/From@g" -e "s@TO_DIR@%{/t:regex_replacement}/Fake@g" %S/Inputs/vfsoverlay-directory-remap.yaml > %t/to-fake.yaml
9+
// RUN: sed -e "s@FROM_DIR@%{/t:regex_replacement}/Fake@g" -e "s@TO_DIR@%{/t:regex_replacement}/To@g" %S/Inputs/vfsoverlay-directory-remap.yaml > %t/from-fake.yaml
10+
11+
// RUN: %clang_cc1 -Werror -fno-pch-timestamp -fvalidate-ast-input-files-content -ivfsoverlay %t/to-fake.yaml -emit-pch -o "%t.pch" %t/From/B.h
12+
13+
// Remove the `From` directory as we don't want to accidentally find that source if the PCH hasn't remapped using the VFS!
14+
// RUN: rm -rf %t/From
15+
16+
// The PCH will be invalid because the `Fake` directory does not exist.
17+
// RUN: not %clang_cc1 -fno-pch-timestamp -fvalidate-ast-input-files-content -verify-pch %t.pch
18+
19+
// But if we specify the correct VFS overlay it'll verify clean.
20+
// RUN: %clang_cc1 -fno-pch-timestamp -fvalidate-ast-input-files-content -verify-pch -ivfsoverlay %t/from-fake.yaml %t.pch
21+
22+
// RUN: %clang_cc1 -fno-pch-timestamp -fvalidate-ast-input-files-content -Werror -I %t/To -ivfsoverlay %t/from-fake.yaml -include-pch "%t.pch" -emit-llvm -C %s -o %t.o
23+
24+
#include "B.h"
25+
26+
int UseSomeFunc() { return SomeFunc(); }

0 commit comments

Comments
 (0)