diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h index 8b4206e52cd48..e1f33d57a8980 100644 --- a/clang/include/clang/Basic/FileManager.h +++ b/clang/include/clang/Basic/FileManager.h @@ -299,6 +299,8 @@ class FileManager : public RefCountedBase { getBufferForFileImpl(StringRef Filename, int64_t FileSize, bool isVolatile, bool RequiresNullTerminator) const; + DirectoryEntry *&getRealDirEntry(const llvm::vfs::Status &Status); + public: /// Get the 'stat' information for the given \p Path. /// diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index 143c04309d075..1dc51deb82987 100644 --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -82,6 +82,22 @@ getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, return FileMgr.getDirectoryRef(DirName, CacheFailure); } +DirectoryEntry *&FileManager::getRealDirEntry(const llvm::vfs::Status &Status) { + assert(Status.isDirectory() && "The directory should exist!"); + // See if we have already opened a directory with the + // same inode (this occurs on Unix-like systems when one dir is + // symlinked to another, for example) or the same path (on + // Windows). + DirectoryEntry *&UDE = UniqueRealDirs[Status.getUniqueID()]; + + if (!UDE) { + // We don't have this directory yet, add it. We use the string + // key from the SeenDirEntries map as the string. + UDE = new (DirsAlloc.Allocate()) DirectoryEntry(); + } + return UDE; +} + /// Add all ancestors of the given path (pointing to either a file or /// a directory) as virtual directories. void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { @@ -99,10 +115,21 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { if (NamedDirEnt.second) return; - // Add the virtual directory to the cache. - auto *UDE = new (DirsAlloc.Allocate()) DirectoryEntry(); - NamedDirEnt.second = *UDE; - VirtualDirectoryEntries.push_back(UDE); + // Check to see if the directory exists. + llvm::vfs::Status Status; + auto statError = + getStatValue(DirName, Status, false, nullptr /*directory lookup*/); + if (statError) { + // There's no real directory at the given path. + // Add the virtual directory to the cache. + auto *UDE = new (DirsAlloc.Allocate()) DirectoryEntry(); + NamedDirEnt.second = *UDE; + VirtualDirectoryEntries.push_back(UDE); + } else { + // There is the real directory + DirectoryEntry *&UDE = getRealDirEntry(Status); + NamedDirEnt.second = *UDE; + } // Recursively add the other ancestors. addAncestorsAsVirtualDirs(DirName); @@ -162,17 +189,8 @@ FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) { return llvm::errorCodeToError(statError); } - // It exists. See if we have already opened a directory with the - // same inode (this occurs on Unix-like systems when one dir is - // symlinked to another, for example) or the same path (on - // Windows). - DirectoryEntry *&UDE = UniqueRealDirs[Status.getUniqueID()]; - - if (!UDE) { - // We don't have this directory yet, add it. We use the string - // key from the SeenDirEntries map as the string. - UDE = new (DirsAlloc.Allocate()) DirectoryEntry(); - } + // It exists. + DirectoryEntry *&UDE = getRealDirEntry(Status); NamedDirEnt.second = *UDE; return DirectoryEntryRef(NamedDirEnt); diff --git a/clang/test/Modules/implicit-module-remap.cpp b/clang/test/Modules/implicit-module-remap.cpp new file mode 100644 index 0000000000000..47927b9694016 --- /dev/null +++ b/clang/test/Modules/implicit-module-remap.cpp @@ -0,0 +1,21 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -fmodules -fmodule-map-file=module.modulemap -fmodules-cache-path=%t -remap-file "test.cpp;%t/test.cpp" %t/test.cpp + +//--- a.h +#define FOO + +//--- module.modulemap +module a { + header "a.h" +} + +//--- test.cpp +#include "a.h" + +#ifndef FOO +#error foo +#endif +