https://github.com/vvereschaka created 
https://github.com/llvm/llvm-project/pull/203662

This commit extends a path prefix mapping provided by `-ffile-prefix-map` 
(`-fmacro-prefix-map`) options to PCH/PCM files in order to support the 
reproducable builds. It uses the prefix map passedvia `-fmacro-prefix-map` 
option to remap the pathes stored within those files.

These changes affect `ORIGINAL_FILE`, `INPUT_FILE` and `MODULE_DIRECTORY` AST 
entries within the PCH/PCM files.

The same prefix maps must be used when emitting the PCH/PCM files 
(`--emit-pch`/`--emit-module`) and during their usage (`--include-pch`/ 
`-fmodule-file`).

Also updated `LangOptions::remapPathPrefix()` method to support a reverse 
mapping for the path prefixes.

>From af1990ff20c05be5844bdda439ed5abc554a755b Mon Sep 17 00:00:00 2001
From: Vladimir Vereschaka <[email protected]>
Date: Wed, 3 Jun 2026 17:17:03 -0700
Subject: [PATCH] [clang][AST] Add path prefix mapping support for PCH/PCM
 files.

This commit extends a path prefix mapping provided by `-ffile-prefix-map`
(`-fmacro-prefix-map`) options to PCH/PCM files in order to support
the reproducable builds. It uses the prefix map passedvia `-fmacro-prefix-map`
option to remap the pathes stored within those files.

These changes affect `ORIGINAL_FILE`, `INPUT_FILE` and `MODULE_DIRECTORY`
AST entries within the PCH/PCM files.

The same prefix maps must be used when emitting the PCH/PCM files
(`--emit-pch`/`--emit-module`) and during their usage (`--include-pch`/
`-fmodule-file`).

Also updated `LangOptions::remapPathPrefix()` method to support a reverse
mapping for the path prefixes.
---
 clang/include/clang/Basic/LangOptions.h       |  7 +-
 clang/include/clang/Serialization/ASTReader.h | 37 ++++++--
 clang/lib/Basic/LangOptions.cpp               | 13 ++-
 .../DependencyScannerImpl.cpp                 |  4 +-
 clang/lib/Frontend/ASTUnit.cpp                |  2 +-
 clang/lib/Frontend/CompilerInstance.cpp       |  2 +-
 clang/lib/Frontend/FrontendActions.cpp        |  2 +-
 clang/lib/Serialization/ASTReader.cpp         | 86 +++++++++++++------
 clang/lib/Serialization/ASTWriter.cpp         |  9 +-
 clang/test/Modules/module-path-prefix-map.cpp | 45 ++++++++++
 clang/test/PCH/pch-path-prefix-map.cpp        | 48 +++++++++++
 11 files changed, 207 insertions(+), 48 deletions(-)
 create mode 100644 clang/test/Modules/module-path-prefix-map.cpp
 create mode 100644 clang/test/PCH/pch-path-prefix-map.cpp

diff --git a/clang/include/clang/Basic/LangOptions.h 
b/clang/include/clang/Basic/LangOptions.h
index 9af036156b1ad..b4ca32b42bcc1 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -796,8 +796,11 @@ class LangOptions : public LangOptionsBase {
 
   bool allowArrayReturnTypes() const { return HLSL; }
 
-  /// Remap path prefix according to -fmacro-prefix-path option.
-  void remapPathPrefix(SmallVectorImpl<char> &Path) const;
+  /// Remap path prefix according to -fmacro-prefix-map option.
+  /// If 'reverse' is true the swapped prefix pair will be used.
+  /// Returns true if Path was changed.
+  bool remapPathPrefix(SmallVectorImpl<char> &Path,
+                       const bool reverse = false) const;
 
   RoundingMode getDefaultRoundingMode() const {
     return RoundingMath ? RoundingMode::Dynamic
diff --git a/clang/include/clang/Serialization/ASTReader.h 
b/clang/include/clang/Serialization/ASTReader.h
index 61bd3d0748988..2809ac2b4e9b5 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -1460,15 +1460,35 @@ class ASTReader : public ExternalPreprocessorSource,
   /// value must go out of scope before the next call to \c 
ResolveImportedPath.
   static TemporarilyOwnedStringRef
   ResolveImportedPath(SmallString<0> &Buf, StringRef Path, StringRef Prefix);
+  /// Resolve \c Path in the context of module file \c M with substitution
+  /// of the path prefixes in case provided them by `-ffile-prefix-map` or
+  /// `-fmacro-prefix-map` options.
+  /// The return value must go out of scope before the next call to
+  /// \c ResolveImportedPath.
+  static TemporarilyOwnedStringRef
+  ResolveImportedPath(SmallString<0> &Buf, StringRef Path, ModuleFile &ModF,
+                      const LangOptions &LangOpts);
+  /// Resolve \c Path in the context of the \c Prefix directory with
+  /// substitution of the path prefixes in case provided them by
+  /// `-ffile-prefix-map` or `-fmacro-prefix-map` options.
+  /// The return value must go out of scope before the next call to
+  /// \c ResolveImportedPath.
+  static TemporarilyOwnedStringRef
+  ResolveImportedPath(SmallString<0> &Buf, StringRef Path, StringRef Prefix,
+                      const LangOptions &LangOpts);
 
   /// Resolve \c Path in the context of module file \c M.
-  static std::string ResolveImportedPathAndAllocate(SmallString<0> &Buf,
-                                                    StringRef Path,
-                                                    ModuleFile &ModF);
+  /// The module path could be remapped with the path prefixes provided by
+  /// `-ffile-prefix-map` or `-fmacro-prefix-map` options.
+  static std::string
+  ResolveImportedPathAndAllocate(SmallString<0> &Buf, StringRef Path,
+                                 ModuleFile &ModF, const LangOptions 
&LangOpts);
   /// Resolve \c Path in the context of the \c Prefix directory.
-  static std::string ResolveImportedPathAndAllocate(SmallString<0> &Buf,
-                                                    StringRef Path,
-                                                    StringRef Prefix);
+  /// The path could be remapped with the path prefixes provided by
+  /// `-ffile-prefix-map` or `-fmacro-prefix-map` options.
+  static std::string
+  ResolveImportedPathAndAllocate(SmallString<0> &Buf, StringRef Path,
+                                 StringRef Prefix, const LangOptions 
&LangOpts);
 
   /// Returns the first key declaration for the given declaration. This
   /// is one that is formerly-canonical (or still canonical) and whose module
@@ -1998,8 +2018,9 @@ class ASTReader : public ExternalPreprocessorSource,
   /// \returns true if an error occurred, false otherwise.
   static bool readASTFileControlBlock(
       StringRef Filename, FileManager &FileMgr, const ModuleCache &ModCache,
-      const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions,
-      ASTReaderListener &Listener, bool ValidateDiagnosticOptions,
+      const PCHContainerReader &PCHContainerRdr, const LangOptions &LangOpts,
+      bool FindModuleFileExtensions, ASTReaderListener &Listener,
+      bool ValidateDiagnosticOptions,
       unsigned ClientLoadCapabilities = ARR_ConfigurationMismatch |
                                         ARR_OutOfDate);
 
diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp
index 7e75bf1221eb7..3c351ea7a985c 100644
--- a/clang/lib/Basic/LangOptions.cpp
+++ b/clang/lib/Basic/LangOptions.cpp
@@ -74,10 +74,15 @@ unsigned LangOptions::getOpenCLCompatibleVersion() const {
   llvm_unreachable("Unknown OpenCL version");
 }
 
-void LangOptions::remapPathPrefix(SmallVectorImpl<char> &Path) const {
-  for (const auto &Entry : MacroPrefixMap)
-    if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
-      break;
+bool LangOptions::remapPathPrefix(SmallVectorImpl<char> &Path,
+                                  const bool reverse /*=false*/) const {
+  for (const auto &Entry : MacroPrefixMap) {
+    const std::string& From = reverse ? Entry.second : Entry.first;
+    const std::string& To = reverse ? Entry.first : Entry.second;
+    if (llvm::sys::path::replace_path_prefix(Path, From, To))
+      return true;
+  }
+  return false;
 }
 
 std::string LangOptions::getOpenCLVersionString() const {
diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
index dc3dbe3603c01..eb34ae2656f09 100644
--- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
@@ -189,7 +189,7 @@ static bool visitPrebuiltModule(StringRef 
PrebuiltModuleFilename,
                            /*DirectlyImported=*/true);
   if (ASTReader::readASTFileControlBlock(
           PrebuiltModuleFilename, CI.getFileManager(), CI.getModuleCache(),
-          CI.getPCHContainerReader(),
+          CI.getPCHContainerReader(), CI.getLangOpts(),
           /*FindModuleFileExtensions=*/false, Listener,
           /*ValidateDiagnosticOptions=*/false, ASTReader::ARR_OutOfDate))
     return true;
@@ -205,7 +205,7 @@ static bool visitPrebuiltModule(StringRef 
PrebuiltModuleFilename,
                              /*DirectlyImported=*/false);
     if (ASTReader::readASTFileControlBlock(
             Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(),
-            CI.getPCHContainerReader(),
+            CI.getPCHContainerReader(), CI.getLangOpts(),
             /*FindModuleFileExtensions=*/false, Listener,
             /*ValidateDiagnosticOptions=*/false))
       return true;
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 2974cf2660184..01cefc1f18ede 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -734,7 +734,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
                              *AST->LangOpts, *AST->CodeGenOpts,
                              *AST->TargetOpts, Counter);
   if (ASTReader::readASTFileControlBlock(
-          Filename, TmpFileMgr, *AST->ModCache, PCHContainerRdr,
+          Filename, TmpFileMgr, *AST->ModCache, PCHContainerRdr, 
*AST->LangOpts,
           /*FindModuleFileExtensions=*/true, Collector,
           /*ValidateDiagnosticOptions=*/true, ASTReader::ARR_None)) {
     AST->getDiagnostics().Report(diag::err_fe_unable_to_load_ast_file);
diff --git a/clang/lib/Frontend/CompilerInstance.cpp 
b/clang/lib/Frontend/CompilerInstance.cpp
index 8aee45b5dc644..1f19e7ac252f8 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -265,7 +265,7 @@ static void collectIncludePCH(CompilerInstance &CI,
     // but only to check whether this is a file containing an AST.
     if (!ASTReader::readASTFileControlBlock(
             Dir->path(), FileMgr, CI.getModuleCache(),
-            CI.getPCHContainerReader(),
+            CI.getPCHContainerReader(), CI.getLangOpts(),
             /*FindModuleFileExtensions=*/false, Validator,
             /*ValidateDiagnosticOptions=*/false))
       MDC->addFile(Dir->path());
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index ba3487d52e380..fac3088a5ad91 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -1010,7 +1010,7 @@ void DumpModuleInfoAction::ExecuteAction() {
   // FileCcontrolBlock is (re-)parsed.
   ASTReader::readASTFileControlBlock(
       getCurrentFile(), FileMgr, CI.getModuleCache(),
-      CI.getPCHContainerReader(),
+      CI.getPCHContainerReader(), CI.getLangOpts(),
       /*FindModuleFileExtensions=*/true, Listener,
       HSOpts.ModulesValidateDiagnosticOptions);
 }
diff --git a/clang/lib/Serialization/ASTReader.cpp 
b/clang/lib/Serialization/ASTReader.cpp
index f8a6a38bb9b5c..6e2ce4ead79df 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -2341,8 +2341,8 @@ HeaderFileInfoTrait::getFile(const internal_key_type 
&Key) {
   if (!Key.Imported)
     return FileMgr.getOptionalFileRef(Key.Filename);
 
-  auto Resolved =
-      ASTReader::ResolveImportedPath(Reader.getPathBuf(), Key.Filename, M);
+  auto Resolved = Reader.ResolveImportedPath(
+      Reader.getPathBuf(), Key.Filename, M, Reader.getContext().getLangOpts());
   return FileMgr.getOptionalFileRef(*Resolved);
 }
 
@@ -2872,8 +2872,8 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned 
ID, bool Complain) {
   time_t StoredTime = FI.StoredTime;
   bool Overridden = FI.Overridden;
   bool Transient = FI.Transient;
-  auto Filename =
-      ResolveImportedPath(PathBuf, FI.UnresolvedImportedFilenameAsRequested, 
F);
+  auto Filename = ResolveImportedPath(
+      PathBuf, FI.UnresolvedImportedFilenameAsRequested, F, PP.getLangOpts());
   uint64_t StoredContentHash = FI.ContentHash;
 
   // For standard C++ modules, we don't need to check the inputs.
@@ -3056,16 +3056,36 @@ ASTReader::ResolveImportedPath(SmallString<0> &Buf, 
StringRef Path,
   return {ResolvedPath, Buf};
 }
 
-std::string ASTReader::ResolveImportedPathAndAllocate(SmallString<0> &Buf,
-                                                      StringRef P,
-                                                      ModuleFile &ModF) {
-  return ResolveImportedPathAndAllocate(Buf, P, ModF.BaseDirectory);
+ASTReader::TemporarilyOwnedStringRef
+ASTReader::ResolveImportedPath(SmallString<0> &Buf, StringRef Path,
+                               StringRef Prefix, const LangOptions &LangOpts) {
+  auto Resolved = ResolveImportedPath(Buf, Path, Prefix);
+
+  Buf.assign(*Resolved);
+  if (LangOpts.remapPathPrefix(Buf, true))
+    return {StringRef{Buf.data(), Buf.size()}, Buf};
+
+  return Resolved;
+}
+
+ASTReader::TemporarilyOwnedStringRef
+ASTReader::ResolveImportedPath(SmallString<0> &Buf, StringRef Path,
+                               ModuleFile &ModF, const LangOptions &LangOpts) {
+  return ResolveImportedPath(Buf, Path, ModF.BaseDirectory, LangOpts);
 }
 
-std::string ASTReader::ResolveImportedPathAndAllocate(SmallString<0> &Buf,
-                                                      StringRef P,
-                                                      StringRef Prefix) {
-  auto ResolvedPath = ResolveImportedPath(Buf, P, Prefix);
+std::string
+ASTReader::ResolveImportedPathAndAllocate(SmallString<0> &Buf, StringRef P,
+                                          ModuleFile &ModF,
+                                          const LangOptions &LangOpts) {
+  return ResolveImportedPathAndAllocate(Buf, P, ModF.BaseDirectory, LangOpts);
+}
+
+std::string
+ASTReader::ResolveImportedPathAndAllocate(SmallString<0> &Buf, StringRef P,
+                                          StringRef Prefix,
+                                          const LangOptions &LangOpts) {
+  auto ResolvedPath = ResolveImportedPath(Buf, P, Prefix, LangOpts);
   return ResolvedPath->str();
 }
 
@@ -3339,7 +3359,8 @@ ASTReader::ReadControlBlock(ModuleFile &F,
           bool IsSystem = I >= NumUserInputs;
           InputFileInfo FI = getInputFileInfo(F, I + 1);
           auto FilenameAsRequested = ResolveImportedPath(
-              PathBuf, FI.UnresolvedImportedFilenameAsRequested, F);
+              PathBuf, FI.UnresolvedImportedFilenameAsRequested, F,
+              PP.getLangOpts());
           Listener->visitInputFile(
               *FilenameAsRequested, IsSystem, FI.Overridden,
               F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule);
@@ -3417,6 +3438,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
     // Read and process a record.
     Record.clear();
     StringRef Blob;
+    SmallString<0> RPath;
     Expected<unsigned> MaybeRecordType =
         Stream.readRecord(Entry.ID, Record, &Blob);
     if (!MaybeRecordType) {
@@ -3603,7 +3625,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
       F.OriginalSourceFileID = FileID::get(Record[0]);
       F.ActualOriginalSourceFileName = std::string(Blob);
       F.OriginalSourceFileName = ResolveImportedPathAndAllocate(
-          PathBuf, F.ActualOriginalSourceFileName, F);
+          PathBuf, F.ActualOriginalSourceFileName, F, PP.getLangOpts());
       break;
 
     case ORIGINAL_FILE_ID:
@@ -3627,10 +3649,15 @@ ASTReader::ReadControlBlock(ModuleFile &F,
 
     case MODULE_DIRECTORY: {
       // Save the BaseDirectory as written in the PCM for computing the module
-      // filename for the ModuleCache.
+      // filename for the ModuleCache. Remap path prefixes if specified.
+      RPath.assign(Blob.begin(), Blob.end());
+      if (PP.getLangOpts().remapPathPrefix(RPath, true))
+        Blob = StringRef(RPath.begin(), RPath.size());
+
       BaseDirectoryAsWritten = Blob;
       assert(!F.ModuleName.empty() &&
              "MODULE_DIRECTORY found before MODULE_NAME");
+
       F.BaseDirectory = std::string(Blob);
 
       auto [MaybeM, IgnoreError] =
@@ -4032,8 +4059,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
     case MODULAR_CODEGEN_DECLS:
       // FIXME: Skip reading this record if our ASTConsumer doesn't care about
       // them (ie: if we're not codegenerating this module).
-      if (F.Kind == MK_MainFile ||
-          getContext().getLangOpts().BuildingPCHWithObjectFile)
+      if (F.Kind == MK_MainFile || PP.getLangOpts().BuildingPCHWithObjectFile)
         for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/)
           EagerlyDeserializedDecls.push_back(ReadDeclID(F, Record, I));
       break;
@@ -5974,9 +6000,9 @@ namespace {
 
 bool ASTReader::readASTFileControlBlock(
     StringRef Filename, FileManager &FileMgr, const ModuleCache &ModCache,
-    const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions,
-    ASTReaderListener &Listener, bool ValidateDiagnosticOptions,
-    unsigned ClientLoadCapabilities) {
+    const PCHContainerReader &PCHContainerRdr, const LangOptions &LangOpts,
+    bool FindModuleFileExtensions, ASTReaderListener &Listener,
+    bool ValidateDiagnosticOptions, unsigned ClientLoadCapabilities) {
   // Open the AST file.
   off_t Size;
   time_t ModTime;
@@ -6124,7 +6150,7 @@ bool ASTReader::readASTFileControlBlock(
     case MODULE_MAP_FILE: {
       unsigned Idx = 0;
       std::string PathStr = ReadString(Record, Idx);
-      auto Path = ResolveImportedPath(PathBuf, PathStr, ModuleDir);
+      auto Path = ResolveImportedPath(PathBuf, PathStr, ModuleDir, LangOpts);
       Listener.ReadModuleMapFile(*Path);
       break;
     }
@@ -6176,13 +6202,13 @@ bool ASTReader::readASTFileControlBlock(
           auto [UnresolvedFilenameAsRequested, UnresolvedFilename] =
               getUnresolvedInputFilenames(Record, Blob);
           auto FilenameAsRequestedBuf = ResolveImportedPath(
-              PathBuf, UnresolvedFilenameAsRequested, ModuleDir);
+              PathBuf, UnresolvedFilenameAsRequested, ModuleDir, LangOpts);
           StringRef Filename;
           if (UnresolvedFilename.empty())
             Filename = *FilenameAsRequestedBuf;
           else {
             auto FilenameBuf = ResolveImportedPath(
-                AdditionalPathBuf, UnresolvedFilename, ModuleDir);
+                AdditionalPathBuf, UnresolvedFilename, ModuleDir, LangOpts);
             Filename = *FilenameBuf;
           }
           shouldContinue = Listener.visitInputFileAsRequested(
@@ -6226,7 +6252,8 @@ bool ASTReader::readASTFileControlBlock(
       Blob = Blob.substr(ASTFileSignature::size);
 
       StringRef FilenameStr = ReadStringBlob(Record, Idx, Blob);
-      auto Filename = ResolveImportedPath(PathBuf, FilenameStr, ModuleDir);
+      auto Filename =
+          ResolveImportedPath(PathBuf, FilenameStr, ModuleDir, LangOpts);
       Listener.visitImport(ModuleName, *Filename);
       break;
     }
@@ -6313,6 +6340,7 @@ bool ASTReader::isAcceptableASTFile(
                                SpecificModuleCachePath, FileMgr,
                                RequireStrictOptionMatches);
   return !readASTFileControlBlock(Filename, FileMgr, ModCache, PCHContainerRdr,
+                                  LangOpts,
                                   /*FindModuleFileExtensions=*/false, 
validator,
                                   /*ValidateDiagnosticOptions=*/true);
 }
@@ -6548,13 +6576,13 @@ Module *ASTReader::getSubmodule(uint32_t GlobalID) {
       break;
 
     case SUBMODULE_TOPHEADER: {
-      auto HeaderName = ResolveImportedPath(PathBuf, Blob, F);
+      auto HeaderName = ResolveImportedPath(PathBuf, Blob, F, 
PP.getLangOpts());
       CurrentModule->addTopHeaderFilename(*HeaderName);
       break;
     }
 
     case SUBMODULE_UMBRELLA_DIR: {
-      auto Dirname = ResolveImportedPath(PathBuf, Blob, F);
+      auto Dirname = ResolveImportedPath(PathBuf, Blob, F, PP.getLangOpts());
       if (auto Umbrella =
               PP.getFileManager().getOptionalDirectoryRef(*Dirname)) {
         if (!CurrentModule->getUmbrellaDirAsWritten()) {
@@ -10464,14 +10492,16 @@ std::string ASTReader::ReadPath(ModuleFile &F, const 
RecordData &Record,
 std::string ASTReader::ReadPath(StringRef BaseDirectory,
                                 const RecordData &Record, unsigned &Idx) {
   std::string Filename = ReadString(Record, Idx);
-  return ResolveImportedPathAndAllocate(PathBuf, Filename, BaseDirectory);
+  return ResolveImportedPathAndAllocate(PathBuf, Filename, BaseDirectory,
+                                        PP.getLangOpts());
 }
 
 std::string ASTReader::ReadPathBlob(StringRef BaseDirectory,
                                     const RecordData &Record, unsigned &Idx,
                                     StringRef &Blob) {
   StringRef Filename = ReadStringBlob(Record, Idx, Blob);
-  return ResolveImportedPathAndAllocate(PathBuf, Filename, BaseDirectory);
+  return ResolveImportedPathAndAllocate(PathBuf, Filename, BaseDirectory,
+                                        PP.getLangOpts());
 }
 
 VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
diff --git a/clang/lib/Serialization/ASTWriter.cpp 
b/clang/lib/Serialization/ASTWriter.cpp
index 21dda6f3733e4..1a43aba60ed41 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -1505,7 +1505,12 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, 
StringRef isysroot) {
         unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
 
         RecordData::value_type Record[] = {MODULE_DIRECTORY};
-        Stream.EmitRecordWithBlob(AbbrevCode, Record, *BaseDir);
+
+        // Remap the path with the prefixes if specified. Write out only
+        // remapped directory, but keep working with the unmodified path.
+        SmallString<0> RPath(*BaseDir);
+        getLangOpts().remapPathPrefix(RPath);
+        Stream.EmitRecordWithBlob(AbbrevCode, Record, RPath);
       }
 
       // Write out all other paths relative to the base directory if possible.
@@ -5417,6 +5422,8 @@ bool 
ASTWriter::PreparePathForOutput(SmallVectorImpl<char> &Path) {
     Path.erase(Path.begin(), Path.begin() + (PathPtr - PathBegin));
     Changed = true;
   }
+  // Remap with the path prefixes if provided.
+  Changed |= getLangOpts().remapPathPrefix(Path);
 
   return Changed;
 }
diff --git a/clang/test/Modules/module-path-prefix-map.cpp 
b/clang/test/Modules/module-path-prefix-map.cpp
new file mode 100644
index 0000000000000..475e82dbe8f49
--- /dev/null
+++ b/clang/test/Modules/module-path-prefix-map.cpp
@@ -0,0 +1,45 @@
+//NOTE: this test reuses the existing include/module files.
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/merge-vtable-codegen
+// RUN: cp -r %S/Inputs/merge-vtable-codegen %t/
+
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fimplicit-module-maps 
-fmodule-name=b -fmodules-cache-path=%t -o %t/b1.pcm \
+// RUN:     -emit-module 
%t/merge-vtable-codegen/merge-vtable-codegen.modulemap \
+// RUN:     -I%t//merge-vtable-codegen -fmacro-prefix-map=%S=x:/PREFIX-MAP-IN 
-fmacro-prefix-map=%t=x:/PREFIX-MAP-OUT
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t/b1.pcm | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-OUT %s 
+
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fimplicit-module-maps 
-fmodule-name=b -fmodules-cache-path=%t -o %t/b1.pcm \
+// RUN:     -emit-module 
%t/merge-vtable-codegen/merge-vtable-codegen.modulemap \
+// RUN:     -I%t/./merge-vtable-codegen -fmacro-prefix-map=%S=x:/PREFIX-MAP-IN 
-fmacro-prefix-map=%t=x:/PREFIX-MAP-OUT
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t/b1.pcm | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-OUT %s 
+
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fimplicit-module-maps 
-fmodule-name=b -fmodules-cache-path=%t -o %t/b1.pcm \
+// RUN:     -emit-module 
%t/merge-vtable-codegen/merge-vtable-codegen.modulemap \
+// RUN:     -I%t/../merge-vtable-codegen 
-fmacro-prefix-map=%S=x:/PREFIX-MAP-IN -fmacro-prefix-map=%t=x:/PREFIX-MAP-OUT
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t/b1.pcm | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-OUT %s 
+
+
+// First, build two modules that both re-export the same header.
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fimplicit-module-maps 
-fmodule-name=b -o %t/b.pcm \
+// RUN:     -emit-module 
%S/Inputs/merge-vtable-codegen/merge-vtable-codegen.modulemap \
+// RUN:     -I%S/Inputs/merge-vtable-codegen 
-fmacro-prefix-map=%S=x:/PREFIX-MAP-IN -fmacro-prefix-map=%t=x:/PREFIX-MAP-OUT
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t/b.pcm | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-IN %s 
+
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fimplicit-module-maps 
-fmodule-name=c -o %t/c.pcm \
+// RUN:     -emit-module 
%S/Inputs/merge-vtable-codegen/merge-vtable-codegen.modulemap \
+// RUN:     -I%S/Inputs/merge-vtable-codegen 
-fmacro-prefix-map=%S=x:/PREFIX-MAP-IN -fmacro-prefix-map=%t=x:/PREFIX-MAP-OUT
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t/c.pcm | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-IN %s 
+
+// Use the two modules in a single compile.
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fimplicit-module-maps 
-fmodule-file=%t/b.pcm -fmodule-file=%t/c.pcm \
+// RUN:     
-fmodule-map-file=%S/Inputs/merge-vtable-codegen/merge-vtable-codegen.modulemap 
 -fmacro-prefix-map=%S=x:/PREFIX-MAP-IN -fmacro-prefix-map=%t=x:/PREFIX-MAP-OUT 
\
+// RUN:     -emit-llvm -o %t/test.o %s
+
+
+// CHECK-PREFIX-MAP-IN: <MODULE_DIRECTORY {{.*}}/> blob data = 
'x:/PREFIX-MAP-IN{{[/\\]}}Inputs{{[/\\]}}merge-vtable-codegen'
+
+// CHECK-PREFIX-MAP-OUT: <MODULE_DIRECTORY {{.*}}/> blob data = 
'x:/PREFIX-MAP-OUT{{[/\\]}}merge-vtable-codegen'
+
+#include "Inputs/merge-vtable-codegen/c.h"
+#include "Inputs/merge-vtable-codegen/b.h"
diff --git a/clang/test/PCH/pch-path-prefix-map.cpp 
b/clang/test/PCH/pch-path-prefix-map.cpp
new file mode 100644
index 0000000000000..eeb520691dace
--- /dev/null
+++ b/clang/test/PCH/pch-path-prefix-map.cpp
@@ -0,0 +1,48 @@
+//NOTE: this test reuses the existing include files.
+
+// Create PCH with mappend path prefixes
+// RUN: mkdir -p %t-dir
+// RUN: cp %S/Inputs/pch-through3.h %t-dir
+// RUN: cp %S/Inputs/pch-through4.h %t-dir
+
+// RUN: %clang_cc1 -I %S -I %t-dir -x c++-header -emit-pch 
-fmacro-prefix-map=%S=x:/PREFIX-MAP-IN 
-fmacro-prefix-map=%t-dir=x:/PREFIX-MAP-OUT \
+// RUN:   -o %t.pch %s
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t.pch | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-ORIGINAL %s 
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t.pch | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-IN %s
+// RUN: rm -f %t.pch
+
+// RUN: %clang_cc1 -I %S -I %t-dir -x c++-header -emit-pch 
-fmacro-prefix-map=%S=x:/PREFIX-MAP-IN 
-fmacro-prefix-map=%t-dir=x:/PREFIX-MAP-OUT \
+// RUN:   -include %S/cmdline-include1.h -include cmdline-include2.h -o %t.pch 
%s
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t.pch | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-ORIGINAL %s 
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t.pch | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-IN-CMD %s
+
+// Use PCH with mapped path prefixes.
+// RUN: %clang_cc1 -I %S -I %t-dir -include-pch %t.pch 
-fmacro-prefix-map=%S=x:/PREFIX-MAP-IN 
-fmacro-prefix-map=%t-dir=x:/PREFIX-MAP-OUT %s
+// RUN: rm -f %t.pch
+
+// RUN: %clang_cl -Werror /I %S /I %t-dir /Yc%s /FI%s /c /Fo%t.pch.obj 
/Fp%t.pch /pathmap:%S=x:/PREFIX-MAP-IN /pathmap:%t-dir=x:/PREFIX-MAP-OUT -- %s
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t.pch | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-ORIGINAL %s 
+// RUN: llvm-bcanalyzer -dump --disable-histogram %t.pch | FileCheck 
-check-prefix=CHECK-PREFIX-MAP-IN %s
+
+// use {{[/\\]}} to follow LLVM_WINDOWS_PREFER_FORWARD_SLASH=ON|OFF on Windows.
+
+// CHECK-PREFIX-MAP-ORIGINAL: <ORIGINAL_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-IN{{[/\\]}}pch-path-prefix-map.cpp'
+// CHECK-PREFIX-MAP-IN: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-IN{{[/\\]}}pch-path-prefix-map.cpp'
+// CHECK-PREFIX-MAP-IN: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-IN{{[/\\]}}Inputs{{[/\\]}}pch-through{{[12]}}.h'
+// CHECK-PREFIX-MAP-IN: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-IN{{[/\\]}}Inputs{{[/\\]}}pch-through{{[12]}}.h'
+// CHECK-PREFIX-MAP-IN: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-OUT{{[/\\]}}pch-through{{[34]}}.h'
+// CHECK-PREFIX-MAP-IN: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-OUT{{[/\\]}}pch-through{{[34]}}.h'
+
+// CHECK-PREFIX-MAP-IN-CMD: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-IN{{[/\\]}}pch-path-prefix-map.cpp'
+// CHECK-PREFIX-MAP-IN-CMD: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-IN{{[/\\]}}cmdline-include{{[12]}}.h'
+// CHECK-PREFIX-MAP-IN-CMD: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-IN{{[/\\]}}cmdline-include{{[12]}}.h'
+// CHECK-PREFIX-MAP-IN-CMD: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-IN{{[/\\]}}Inputs{{[/\\]}}pch-through{{[12]}}.h'
+// CHECK-PREFIX-MAP-IN-CMD: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-IN{{[/\\]}}Inputs{{[/\\]}}pch-through{{[12]}}.h'
+// CHECK-PREFIX-MAP-IN-CMD: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-OUT{{[/\\]}}pch-through{{[34]}}.h'
+// CHECK-PREFIX-MAP-IN-CMD: <INPUT_FILE {{.*}}/> blob data = 
'x:/PREFIX-MAP-OUT{{[/\\]}}pch-through{{[34]}}.h'
+
+#include "Inputs/pch-through1.h"
+#include "Inputs/pch-through2.h"
+#include "pch-through3.h"
+#include <pch-through4.h>
+

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to