@@ -415,6 +415,97 @@ static llvm::Error resolveExplicitModuleInputs(
415415 return llvm::Error::success ();
416416}
417417
418+ static llvm::Error pruneUnusedVFSOverlays (
419+ ModuleDependencyID moduleID, const ModuleDependencyInfo &resolvingDepInfo,
420+ const std::set<ModuleDependencyID> &dependencies,
421+ ModuleDependenciesCache &cache, CompilerInstance &instance) {
422+ auto isVFSOverlayFlag = [](StringRef arg) {
423+ return arg == " -ivfsoverlay" || arg == " -vfsoverlay" ;
424+ };
425+ auto isXCCArg = [](StringRef arg) {
426+ return arg == " -Xcc" ;
427+ };
428+
429+ // Pruning of unused VFS overlay options for Clang dependencies
430+ // is performed by the Clang dependency scanner.
431+ if (!resolvingDepInfo.isSwiftModule ())
432+ return llvm::Error::success ();
433+
434+ // If this Swift dependency contains any VFS overlay paths,
435+ // then attempt to prune the ones not used by any of the Clang dependencies.
436+ if (!llvm::any_of (resolvingDepInfo.getCommandline (),
437+ [&isVFSOverlayFlag](const std::string &arg) {
438+ return isVFSOverlayFlag (arg);
439+ }))
440+ return llvm::Error::success ();
441+
442+ // 1. For each Clang dependency, gather its ivfsoverlay path arguments
443+ // to keep track of which overlays are actually used and were not
444+ // pruned by the Clang dependency scanner.
445+ llvm::StringSet<> usedVFSOverlayPaths;
446+ for (const auto &depModuleID : dependencies) {
447+ const auto optionalDepInfo = cache.findDependency (depModuleID);
448+ assert (optionalDepInfo.has_value ());
449+ const auto depInfo = optionalDepInfo.value ();
450+ if (auto clangDepDetails = depInfo->getAsClangModule ()) {
451+ const auto &depCommandLine = clangDepDetails->buildCommandLine ;
452+ // true if the previous argument was the dash-option of an option pair
453+ bool getNext = false ;
454+ for (const auto &A : depCommandLine) {
455+ StringRef arg (A);
456+ if (isXCCArg (arg))
457+ continue ;
458+ if (getNext) {
459+ getNext = false ;
460+ usedVFSOverlayPaths.insert (arg);
461+ } else if (isVFSOverlayFlag (arg))
462+ getNext = true ;
463+ }
464+ }
465+ }
466+
467+ // 2. Each -Xcc VFS overlay path on the resolving command-line which is not used by
468+ // any of the Clang dependencies can be removed from the command-line.
469+ const std::vector<std::string> ¤tCommandLine =
470+ resolvingDepInfo.getCommandline ();
471+ std::vector<std::string> resolvedCommandLine;
472+ size_t skip = 0 ;
473+ for (auto it = currentCommandLine.begin (), end = currentCommandLine.end ();
474+ it != end; it++) {
475+ if (skip) {
476+ skip--;
477+ continue ;
478+ }
479+ // If this VFS overlay was not used across any of the dependencies, skip it.
480+ if ((it+1 ) != end && isXCCArg (*it) && isVFSOverlayFlag (*(it + 1 ))) {
481+ assert (it + 2 != end); // Extra -Xcc
482+ assert (it + 3 != end); // Actual VFS overlay path argument
483+ if (!usedVFSOverlayPaths.contains (*(it + 3 ))) {
484+ skip = 3 ;
485+ continue ;
486+ }
487+ }
488+ resolvedCommandLine.push_back (*it);
489+ }
490+
491+ // 3. Update the dependency in the cache if the command-line has been modified.
492+ if (currentCommandLine.size () != resolvedCommandLine.size ()) {
493+ auto dependencyInfoCopy = resolvingDepInfo;
494+ dependencyInfoCopy.updateCommandLine (resolvedCommandLine);
495+
496+ // Update the CAS cache key for the new command-line
497+ if (instance.getInvocation ().getCASOptions ().EnableCaching ) {
498+ auto &CAS = cache.getScanService ().getSharedCachingFS ().getCAS ();
499+ auto Key = updateModuleCacheKey (dependencyInfoCopy, cache, CAS);
500+ if (!Key)
501+ return Key.takeError ();
502+ }
503+ cache.updateDependency (moduleID, dependencyInfoCopy);
504+ }
505+
506+ return llvm::Error::success ();
507+ }
508+
418509namespace {
419510std::string quote (StringRef unquoted) {
420511 llvm::SmallString<128 > buffer;
@@ -1658,7 +1749,7 @@ swift::dependencies::createEncodedModuleKindAndName(ModuleDependencyID id) {
16581749 }
16591750}
16601751
1661- static void resolveDependencyInputCommandLineArguments (
1752+ static void resolveDependencyCommandLineArguments (
16621753 CompilerInstance &instance, ModuleDependenciesCache &cache,
16631754 const std::vector<ModuleDependencyID> &topoSortedModuleList) {
16641755 auto moduleTransitiveClosures =
@@ -1676,6 +1767,11 @@ static void resolveDependencyInputCommandLineArguments(
16761767 cache, instance))
16771768 instance.getDiags ().diagnose (SourceLoc (), diag::error_cas,
16781769 toString (std::move (E)));
1770+
1771+ if (auto E = pruneUnusedVFSOverlays (modID, *deps, dependencyClosure,
1772+ cache, instance))
1773+ instance.getDiags ().diagnose (SourceLoc (), diag::error_cas,
1774+ toString (std::move (E)));
16791775 }
16801776}
16811777
@@ -1756,8 +1852,8 @@ swift::dependencies::performModuleScan(CompilerInstance &instance,
17561852
17571853 auto topologicallySortedModuleList =
17581854 computeTopologicalSortOfExplicitDependencies (allModules, cache);
1759- resolveDependencyInputCommandLineArguments (instance, cache,
1760- topologicallySortedModuleList);
1855+ resolveDependencyCommandLineArguments (instance, cache,
1856+ topologicallySortedModuleList);
17611857
17621858 updateDependencyTracker (instance, cache, allModules);
17631859 return generateFullDependencyGraph (instance, cache,
0 commit comments