Skip to content

Commit 470d6de

Browse files
committed
[scanner] setup the clang importer injected redirecting overlay vfs for correct clang dependency scanning
This makes its possible to use -explicit-module-build to correctly find 'crt' swift module on windows
1 parent 8715c34 commit 470d6de

File tree

5 files changed

+105
-35
lines changed

5 files changed

+105
-35
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,14 @@ ClangInvocationFileMapping getClangInvocationFileMapping(
753753
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = nullptr,
754754
bool suppressDiagnostic = false);
755755

756+
/// Construct the clang overlay VFS that's needed for the clang instance
757+
/// used by the clang importer to find injected platform-specific modulemaps
758+
/// that are created by `getClangInvocationFileMapping`.
759+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
760+
createClangInvocationFileMappingVFS(
761+
const ClangInvocationFileMapping &fileMapping, ASTContext &ctx,
762+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseVFS);
763+
756764
} // end namespace swift
757765

758766
#endif

lib/ClangImporter/ClangImporter.cpp

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,39 +1318,8 @@ ClangImporter::create(ASTContext &ctx,
13181318
// Avoid creating indirect file system when using include tree.
13191319
if (!ctx.ClangImporterOpts.HasClangIncludeTreeRoot) {
13201320
// Wrap Swift's FS to allow Clang to override the working directory
1321-
VFS = llvm::vfs::RedirectingFileSystem::create(
1322-
fileMapping.redirectedFiles, true, *ctx.SourceMgr.getFileSystem());
1323-
if (importerOpts.DumpClangDiagnostics) {
1324-
llvm::errs() << "clang importer redirected file mappings:\n";
1325-
for (const auto &mapping : fileMapping.redirectedFiles) {
1326-
llvm::errs() << " mapping real file '" << mapping.second
1327-
<< "' to virtual file '" << mapping.first << "'\n";
1328-
}
1329-
llvm::errs() << "\n";
1330-
}
1331-
1332-
if (!fileMapping.overridenFiles.empty()) {
1333-
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> overridenVFS =
1334-
new llvm::vfs::InMemoryFileSystem();
1335-
for (const auto &file : fileMapping.overridenFiles) {
1336-
if (importerOpts.DumpClangDiagnostics) {
1337-
llvm::errs() << "clang importer overriding file '" << file.first
1338-
<< "' with the following contents:\n";
1339-
llvm::errs() << file.second << "\n";
1340-
}
1341-
auto contents = ctx.Allocate<char>(file.second.size() + 1);
1342-
std::copy(file.second.begin(), file.second.end(), contents.begin());
1343-
// null terminate the buffer.
1344-
contents[contents.size() - 1] = '\0';
1345-
overridenVFS->addFile(file.first, 0,
1346-
llvm::MemoryBuffer::getMemBuffer(StringRef(
1347-
contents.begin(), contents.size() - 1)));
1348-
}
1349-
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> overlayVFS =
1350-
new llvm::vfs::OverlayFileSystem(VFS);
1351-
VFS = overlayVFS;
1352-
overlayVFS->pushOverlay(overridenVFS);
1353-
}
1321+
VFS = createClangInvocationFileMappingVFS(fileMapping, ctx,
1322+
ctx.SourceMgr.getFileSystem());
13541323
}
13551324

13561325
// Create a new Clang compiler invocation.

lib/ClangImporter/ClangIncludePaths.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,5 +634,46 @@ ClangInvocationFileMapping swift::getClangInvocationFileMapping(
634634

635635
GetWindowsFileMappings(result, ctx, vfs,
636636
result.requiresBuiltinHeadersInSystemModules);
637+
637638
return result;
638639
}
640+
641+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
642+
swift::createClangInvocationFileMappingVFS(
643+
const ClangInvocationFileMapping &fileMapping, ASTContext &ctx,
644+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseVFS) {
645+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> redirectedVFS =
646+
llvm::vfs::RedirectingFileSystem::create(fileMapping.redirectedFiles,
647+
true, *baseVFS);
648+
if (ctx.ClangImporterOpts.DumpClangDiagnostics) {
649+
llvm::errs() << "clang importer redirected file mappings:\n";
650+
for (const auto &mapping : fileMapping.redirectedFiles) {
651+
llvm::errs() << " mapping real file '" << mapping.second
652+
<< "' to virtual file '" << mapping.first << "'\n";
653+
}
654+
llvm::errs() << "\n";
655+
}
656+
657+
if (fileMapping.overridenFiles.empty())
658+
return redirectedVFS;
659+
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> overridenVFS =
660+
new llvm::vfs::InMemoryFileSystem();
661+
for (const auto &file : fileMapping.overridenFiles) {
662+
if (ctx.ClangImporterOpts.DumpClangDiagnostics) {
663+
llvm::errs() << "clang importer overriding file '" << file.first
664+
<< "' with the following contents:\n";
665+
llvm::errs() << file.second << "\n";
666+
}
667+
auto contents = ctx.Allocate<char>(file.second.size() + 1);
668+
std::copy(file.second.begin(), file.second.end(), contents.begin());
669+
// null terminate the buffer.
670+
contents[contents.size() - 1] = '\0';
671+
overridenVFS->addFile(file.first, 0,
672+
llvm::MemoryBuffer::getMemBuffer(StringRef(
673+
contents.begin(), contents.size() - 1)));
674+
}
675+
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> overlayVFS =
676+
new llvm::vfs::OverlayFileSystem(redirectedVFS);
677+
overlayVFS->pushOverlay(overridenVFS);
678+
return overlayVFS;
679+
}

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,54 @@ static bool isSwiftDependencyKind(ModuleDependencyKind Kind) {
169169
Kind == ModuleDependencyKind::SwiftPlaceholder;
170170
}
171171

172+
// Wrap the clang file mapping overlay filesystems in a proxy filesystem,
173+
// to avoid enumerating the overlay filesystems in a `visitChildFileSystems`,
174+
// as clang's dependency scanner tries to validate that the number of
175+
// overlay file systems used is the same as the number of `-ivfsoverlay`
176+
// flags passed through the clang invocation. This validation causes an
177+
// assertion failure if the filesystem isn't hidden.
178+
// We don't need to expose the clang importer overlay filesystem to clang's
179+
// dependency scanner, as it only needs to optimize overlay VFS that are
180+
// explicitly passed to it via `-ivfsoverlay`.
181+
class SilentClangImporterOverlayWrapperFS : public llvm::vfs::ProxyFileSystem {
182+
public:
183+
SilentClangImporterOverlayWrapperFS(
184+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
185+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseFS)
186+
: llvm::vfs::ProxyFileSystem(fs), baseFS(baseFS) {}
187+
188+
void visitChildFileSystems(VisitCallbackTy Callback) override {
189+
// Do not forward to proxy, instead count the base and forward
190+
// to base directly, bypassing the installed clang overlay filesystems.
191+
if (baseFS) {
192+
Callback(*baseFS);
193+
baseFS->visitChildFileSystems(Callback);
194+
}
195+
}
196+
197+
private:
198+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseFS;
199+
};
200+
201+
static llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
202+
getClangInvocationOverlayScanningVFS(
203+
ASTContext &ctx, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseFS) {
204+
auto fileMapping = swift::getClangInvocationFileMapping(
205+
ctx, baseFS, /*suppressDiagnostic=*/true);
206+
if (fileMapping.redirectedFiles.empty())
207+
return baseFS;
208+
return createClangInvocationFileMappingVFS(fileMapping, ctx, baseFS);
209+
}
210+
172211
ModuleDependencyScanningWorker::ModuleDependencyScanningWorker(
173212
SwiftDependencyScanningService &globalScanningService,
174213
const CompilerInvocation &ScanCompilerInvocation,
175214
const SILOptions &SILOptions, ASTContext &ScanASTContext,
176215
swift::DependencyTracker &DependencyTracker, DiagnosticEngine &Diagnostics)
177-
: clangScanningTool(*globalScanningService.ClangScanningService,
178-
globalScanningService.getClangScanningFS()) {
216+
: clangScanningTool(
217+
*globalScanningService.ClangScanningService,
218+
getClangInvocationOverlayScanningVFS(
219+
ScanASTContext, globalScanningService.getClangScanningFS())) {
179220
// Create a scanner-specific Invocation and ASTContext.
180221
workerCompilerInvocation =
181222
std::make_unique<CompilerInvocation>(ScanCompilerInvocation);

test/ScanDependencies/win-crt.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -scan-dependencies -Xcc -v %s -o - | %validate-json | %FileCheck %s
3+
4+
// We want to explicitly import WinSDK's CRT.
5+
// REQUIRES: OS=windows-msvc
6+
7+
import CRT
8+
9+
// CHECK: "modulePath": "{{.*}}\\ucrt-{{.*}}.pcm",
10+
// CHECK-NEXT: "sourceFiles": [
11+
// CHECK-NEXT: "{{.*}}\\ucrt\\module.modulemap"

0 commit comments

Comments
 (0)