[PATCH] D66710: ASTReader: Bypass overridden files when reading PCHs

2019-08-30 Thread Duncan P. N. Exon Smith via Phabricator via cfe-commits
dexonsmith closed this revision.
dexonsmith marked an inline comment as done.
dexonsmith added a comment.

r370546.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66710/new/

https://reviews.llvm.org/D66710



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66710: ASTReader: Bypass overridden files when reading PCHs

2019-08-30 Thread Bruno Cardoso Lopes via Phabricator via cfe-commits
bruno accepted this revision.
bruno added a comment.

LGTM!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66710/new/

https://reviews.llvm.org/D66710



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66710: ASTReader: Bypass overridden files when reading PCHs

2019-08-29 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman accepted this revision.
arphaman added a comment.
This revision is now accepted and ready to land.

LGTM


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66710/new/

https://reviews.llvm.org/D66710



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66710: ASTReader: Bypass overridden files when reading PCHs

2019-08-28 Thread Duncan P. N. Exon Smith via Phabricator via cfe-commits
dexonsmith marked 2 inline comments as done.
dexonsmith added inline comments.



Comment at: clang/include/clang/Basic/FileManager.h:320
+  /// twice, you get two new file entries.
+  const FileEntry *getBypassFile(const FileEntry );
+

bruno wrote:
> Does it make sense to return/read from a FileEntryRef here? @arphaman, wdyt?
SGTM.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66710/new/

https://reviews.llvm.org/D66710



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66710: ASTReader: Bypass overridden files when reading PCHs

2019-08-28 Thread Duncan P. N. Exon Smith via Phabricator via cfe-commits
dexonsmith updated this revision to Diff 217754.
dexonsmith added a comment.

Added a FileManagerTest and changed FileManager::getBypassFile to use 
FileEntryRef.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66710/new/

https://reviews.llvm.org/D66710

Files:
  clang/include/clang/Basic/FileManager.h
  clang/include/clang/Basic/SourceManager.h
  clang/lib/Basic/FileManager.cpp
  clang/lib/Basic/SourceManager.cpp
  clang/lib/Serialization/ASTReader.cpp
  clang/unittests/Basic/FileManagerTest.cpp

Index: clang/unittests/Basic/FileManagerTest.cpp
===
--- clang/unittests/Basic/FileManagerTest.cpp
+++ clang/unittests/Basic/FileManagerTest.cpp
@@ -397,4 +397,54 @@
   EXPECT_EQ((*file)->tryGetRealPathName(), ExpectedResult);
 }
 
+TEST_F(FileManagerTest, getBypassFile) {
+  SmallString<64> CustomWorkingDir;
+#ifdef _WIN32
+  CustomWorkingDir = "C:/";
+#else
+  CustomWorkingDir = "/";
+#endif
+
+  auto FS = IntrusiveRefCntPtr(
+  new llvm::vfs::InMemoryFileSystem);
+  // setCurrentworkingdirectory must finish without error.
+  ASSERT_TRUE(!FS->setCurrentWorkingDirectory(CustomWorkingDir));
+
+  FileSystemOptions Opts;
+  FileManager Manager(Opts, FS);
+
+  // Inject fake files into the file system.
+  auto Cache = std::make_unique();
+  Cache->InjectDirectory("/tmp", 42);
+  Cache->InjectFile("/tmp/test", 43);
+  Manager.setStatCache(std::move(Cache));
+
+  // Set up a virtual file with a different size than FakeStatCache uses.
+  const FileEntry *File = Manager.getVirtualFile("/tmp/test", /*Size=*/10, 0);
+  ASSERT_TRUE(File);
+  FileEntryRef Ref("/tmp/test", *File);
+  EXPECT_TRUE(Ref.isValid());
+  EXPECT_EQ(Ref.getSize(), 10);
+
+  // Calling a second time should not affect the UID or size.
+  unsigned VirtualUID = Ref.getUID();
+  EXPECT_EQ(*expectedToOptional(Manager.getFileRef("/tmp/test")), Ref);
+  EXPECT_EQ(Ref.getUID(), VirtualUID);
+  EXPECT_EQ(Ref.getSize(), 10);
+
+  // Bypass the file.
+  llvm::Optional BypassRef = Manager.getBypassFile(Ref);
+  ASSERT_TRUE(BypassRef);
+  EXPECT_TRUE(BypassRef->isValid());
+  EXPECT_EQ(BypassRef->getName(), Ref.getName());
+
+  // Check that it's different in the right ways.
+  EXPECT_NE(>getFileEntry(), File);
+  EXPECT_NE(BypassRef->getUID(), VirtualUID);
+  EXPECT_NE(BypassRef->getSize(), Ref.getSize());
+
+  // The virtual file should still be returned when searching.
+  EXPECT_EQ(*expectedToOptional(Manager.getFileRef("/tmp/test")), Ref);
+}
+
 } // anonymous namespace
Index: clang/lib/Serialization/ASTReader.cpp
===
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -2315,19 +2315,14 @@
   if ((!Overridden && !Transient) && SM.isFileOverridden(File)) {
 if (Complain)
   Error(diag::err_fe_pch_file_overridden, Filename);
-// After emitting the diagnostic, recover by disabling the override so
-// that the original file will be used.
-//
-// FIXME: This recovery is just as broken as the original state; there may
-// be another precompiled module that's using the overridden contents, or
-// we might be half way through parsing it. Instead, we should treat the
-// overridden contents as belonging to a separate FileEntry.
-SM.disableFileContentsOverride(File);
-// The FileEntry is a virtual file entry with the size of the contents
-// that would override the original contents. Set it to the original's
-// size/time.
-FileMgr.modifyFileEntry(const_cast(File),
-StoredSize, StoredTime);
+
+// After emitting the diagnostic, bypass the overriding file to recover
+// (this creates a separate FileEntry).
+File = SM.bypassFileContentsOverride(*File);
+if (!File) {
+  F.InputFilesLoaded[ID - 1] = InputFile::getNotFound();
+  return InputFile();
+}
   }
 
   bool IsOutOfDate = false;
Index: clang/lib/Basic/SourceManager.cpp
===
--- clang/lib/Basic/SourceManager.cpp
+++ clang/lib/Basic/SourceManager.cpp
@@ -669,17 +669,19 @@
   getOverriddenFilesInfo().OverriddenFiles[SourceFile] = NewFile;
 }
 
-void SourceManager::disableFileContentsOverride(const FileEntry *File) {
-  if (!isFileOverridden(File))
-return;
-
-  const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
-  const_cast(IR)->replaceBuffer(nullptr);
-  const_cast(IR)->ContentsEntry = IR->OrigEntry;
+const FileEntry *
+SourceManager::bypassFileContentsOverride(const FileEntry ) {
+  assert(isFileOverridden());
+  llvm::Optional BypassFile =
+  FileMgr.getBypassFile(FileEntryRef(File.getName(), File));
+
+  // If the file can't be found in the FS, give up.
+  if (!BypassFile)
+return nullptr;
 
-  assert(OverriddenFilesInfo);
-  OverriddenFilesInfo->OverriddenFiles.erase(File);
-  OverriddenFilesInfo->OverriddenFilesWithBuffer.erase(File);
+  const 

[PATCH] D66710: ASTReader: Bypass overridden files when reading PCHs

2019-08-28 Thread Bruno Cardoso Lopes via Phabricator via cfe-commits
bruno added a comment.

Nice! Is this something that can be tested for in 
`unittests/Basic/FileManagerTest.cpp`?




Comment at: clang/include/clang/Basic/FileManager.h:320
+  /// twice, you get two new file entries.
+  const FileEntry *getBypassFile(const FileEntry );
+

Does it make sense to return/read from a FileEntryRef here? @arphaman, wdyt?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66710/new/

https://reviews.llvm.org/D66710



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66710: ASTReader: Bypass overridden files when reading PCHs

2019-08-26 Thread Duncan P. N. Exon Smith via Phabricator via cfe-commits
dexonsmith updated this revision to Diff 217229.
dexonsmith added a comment.

New diff with full context.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66710/new/

https://reviews.llvm.org/D66710

Files:
  clang/include/clang/Basic/FileManager.h
  clang/include/clang/Basic/SourceManager.h
  clang/lib/Basic/FileManager.cpp
  clang/lib/Basic/SourceManager.cpp
  clang/lib/Serialization/ASTReader.cpp

Index: clang/lib/Serialization/ASTReader.cpp
===
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -2315,19 +2315,14 @@
   if ((!Overridden && !Transient) && SM.isFileOverridden(File)) {
 if (Complain)
   Error(diag::err_fe_pch_file_overridden, Filename);
-// After emitting the diagnostic, recover by disabling the override so
-// that the original file will be used.
-//
-// FIXME: This recovery is just as broken as the original state; there may
-// be another precompiled module that's using the overridden contents, or
-// we might be half way through parsing it. Instead, we should treat the
-// overridden contents as belonging to a separate FileEntry.
-SM.disableFileContentsOverride(File);
-// The FileEntry is a virtual file entry with the size of the contents
-// that would override the original contents. Set it to the original's
-// size/time.
-FileMgr.modifyFileEntry(const_cast(File),
-StoredSize, StoredTime);
+
+// After emitting the diagnostic, bypass the overriding file to recover
+// (this creates a separate FileEntry).
+File = SM.bypassFileContentsOverride(*File);
+if (!File) {
+  F.InputFilesLoaded[ID - 1] = InputFile::getNotFound();
+  return InputFile();
+}
   }
 
   bool IsOutOfDate = false;
Index: clang/lib/Basic/SourceManager.cpp
===
--- clang/lib/Basic/SourceManager.cpp
+++ clang/lib/Basic/SourceManager.cpp
@@ -671,17 +671,17 @@
   getOverriddenFilesInfo().OverriddenFiles[SourceFile] = NewFile;
 }
 
-void SourceManager::disableFileContentsOverride(const FileEntry *File) {
-  if (!isFileOverridden(File))
-return;
+const FileEntry *
+SourceManager::bypassFileContentsOverride(const FileEntry ) {
+  assert(isFileOverridden());
+  auto *BypassFile = FileMgr.getBypassFile(File);
 
-  const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
-  const_cast(IR)->replaceBuffer(nullptr);
-  const_cast(IR)->ContentsEntry = IR->OrigEntry;
+  // If the file can't be found in the FS, give up.
+  if (!BypassFile)
+return nullptr;
 
-  assert(OverriddenFilesInfo);
-  OverriddenFilesInfo->OverriddenFiles.erase(File);
-  OverriddenFilesInfo->OverriddenFilesWithBuffer.erase(File);
+  (void)getOrCreateContentCache(BypassFile);
+  return BypassFile;
 }
 
 void SourceManager::setFileIsTransient(const FileEntry *File) {
Index: clang/lib/Basic/FileManager.cpp
===
--- clang/lib/Basic/FileManager.cpp
+++ clang/lib/Basic/FileManager.cpp
@@ -389,6 +389,24 @@
   return UFE;
 }
 
+const FileEntry *FileManager::getBypassFile(const FileEntry ) {
+  // Stat of the file and return nullptr if it doesn't exist.
+  llvm::vfs::Status Status;
+  if (getStatValue(VFE.Name, Status, /*isFile=*/true, /*F=*/nullptr))
+return nullptr;
+
+  // Fill it in from the stat.
+  BypassFileEntries.push_back(std::make_unique());
+  auto  = *BypassFileEntries.back();
+  BFE.Name = VFE.Name;
+  BFE.Size = Status.getSize();
+  BFE.Dir = VFE.Dir;
+  BFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
+  BFE.UID = NextFileUID++;
+  BFE.IsValid = true;
+  return 
+}
+
 bool FileManager::FixupRelativePath(SmallVectorImpl ) const {
   StringRef pathRef(path.data(), path.size());
 
@@ -532,12 +550,6 @@
 UIDToFiles[VFE->getUID()] = VFE.get();
 }
 
-void FileManager::modifyFileEntry(FileEntry *File,
-  off_t Size, time_t ModificationTime) {
-  File->Size = Size;
-  File->ModTime = ModificationTime;
-}
-
 StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
   // FIXME: use llvm::sys::fs::canonical() when it gets implemented
   llvm::DenseMap::iterator Known
Index: clang/include/clang/Basic/SourceManager.h
===
--- clang/include/clang/Basic/SourceManager.h
+++ clang/include/clang/Basic/SourceManager.h
@@ -952,11 +952,12 @@
 return false;
   }
 
-  /// Disable overridding the contents of a file, previously enabled
-  /// with #overrideFileContents.
+  /// Bypass the overridden contents of a file.  This creates a new FileEntry
+  /// and initializes the content cache for it.  Returns nullptr if there is no
+  /// such file in the filesystem.
   ///
   /// This should be called before parsing has begun.
-  void disableFileContentsOverride(const FileEntry *File);
+  const 

[PATCH] D66710: ASTReader: Bypass overridden files when reading PCHs

2019-08-26 Thread Alex Lorenz via Phabricator via cfe-commits
arphaman added a comment.

Missing full context


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66710/new/

https://reviews.llvm.org/D66710



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66710: ASTReader: Bypass overridden files when reading PCHs

2019-08-24 Thread Duncan P. N. Exon Smith via Phabricator via cfe-commits
dexonsmith created this revision.
dexonsmith added reviewers: rsmith, arphaman, akyrtzi, bruno.
Herald added a subscriber: ributzka.

If contents of a file that is part of a PCM are overridden when reading
it, but weren't overridden when the PCM was being built, the ASTReader
will emit an error.  Now it creates a separate FileEntry for recovery,
bypassing the overridden content instead of discarding it.  The
pre-existing testcase clang/test/PCH/remap-file-from-pch.cpp confirms
that the new recovery method works correctly.

This resolves a long-standing FIXME to avoid hypothetically invalidating
another precompiled module that's already using the overridden contents.

This also removes ContentCache-related API that would be unsafe to use
across `CompilerInstance`s in an implicit modules build.  This helps to
unblock us sinking it from SourceManager into FileManager in the future,
which would allow us to delete `InMemoryModuleCache`.


https://reviews.llvm.org/D66710

Files:
  clang/include/clang/Basic/FileManager.h
  clang/include/clang/Basic/SourceManager.h
  clang/lib/Basic/FileManager.cpp
  clang/lib/Basic/SourceManager.cpp
  clang/lib/Serialization/ASTReader.cpp

Index: clang/lib/Serialization/ASTReader.cpp
===
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -2315,19 +2315,14 @@
   if ((!Overridden && !Transient) && SM.isFileOverridden(File)) {
 if (Complain)
   Error(diag::err_fe_pch_file_overridden, Filename);
-// After emitting the diagnostic, recover by disabling the override so
-// that the original file will be used.
-//
-// FIXME: This recovery is just as broken as the original state; there may
-// be another precompiled module that's using the overridden contents, or
-// we might be half way through parsing it. Instead, we should treat the
-// overridden contents as belonging to a separate FileEntry.
-SM.disableFileContentsOverride(File);
-// The FileEntry is a virtual file entry with the size of the contents
-// that would override the original contents. Set it to the original's
-// size/time.
-FileMgr.modifyFileEntry(const_cast(File),
-StoredSize, StoredTime);
+
+// After emitting the diagnostic, bypass the overriding file to recover
+// (this creates a separate FileEntry).
+File = SM.bypassFileContentsOverride(*File);
+if (!File) {
+  F.InputFilesLoaded[ID - 1] = InputFile::getNotFound();
+  return InputFile();
+}
   }
 
   bool IsOutOfDate = false;
Index: clang/lib/Basic/SourceManager.cpp
===
--- clang/lib/Basic/SourceManager.cpp
+++ clang/lib/Basic/SourceManager.cpp
@@ -671,17 +671,17 @@
   getOverriddenFilesInfo().OverriddenFiles[SourceFile] = NewFile;
 }
 
-void SourceManager::disableFileContentsOverride(const FileEntry *File) {
-  if (!isFileOverridden(File))
-return;
+const FileEntry *
+SourceManager::bypassFileContentsOverride(const FileEntry ) {
+  assert(isFileOverridden());
+  auto *BypassFile = FileMgr.getBypassFile(File);
 
-  const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
-  const_cast(IR)->replaceBuffer(nullptr);
-  const_cast(IR)->ContentsEntry = IR->OrigEntry;
+  // If the file can't be found in the FS, give up.
+  if (!BypassFile)
+return nullptr;
 
-  assert(OverriddenFilesInfo);
-  OverriddenFilesInfo->OverriddenFiles.erase(File);
-  OverriddenFilesInfo->OverriddenFilesWithBuffer.erase(File);
+  (void)getOrCreateContentCache(BypassFile);
+  return BypassFile;
 }
 
 void SourceManager::setFileIsTransient(const FileEntry *File) {
Index: clang/lib/Basic/FileManager.cpp
===
--- clang/lib/Basic/FileManager.cpp
+++ clang/lib/Basic/FileManager.cpp
@@ -389,6 +389,24 @@
   return UFE;
 }
 
+const FileEntry *FileManager::getBypassFile(const FileEntry ) {
+  // Stat of the file and return nullptr if it doesn't exist.
+  llvm::vfs::Status Status;
+  if (getStatValue(VFE.Name, Status, /*isFile=*/true, /*F=*/nullptr))
+return nullptr;
+
+  // Fill it in from the stat.
+  BypassFileEntries.push_back(std::make_unique());
+  auto  = *BypassFileEntries.back();
+  BFE.Name = VFE.Name;
+  BFE.Size = Status.getSize();
+  BFE.Dir = VFE.Dir;
+  BFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
+  BFE.UID = NextFileUID++;
+  BFE.IsValid = true;
+  return 
+}
+
 bool FileManager::FixupRelativePath(SmallVectorImpl ) const {
   StringRef pathRef(path.data(), path.size());
 
@@ -532,12 +550,6 @@
 UIDToFiles[VFE->getUID()] = VFE.get();
 }
 
-void FileManager::modifyFileEntry(FileEntry *File,
-  off_t Size, time_t ModificationTime) {
-  File->Size = Size;
-  File->ModTime = ModificationTime;
-}
-
 StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
   // FIXME: use