<div dir="ltr"><div dir="ltr">I don't have a reduced test case yet, but this seems to cause clang to sometimes claim that an included file isn't found even if it's there, at least on macOS: <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=924225">https://bugs.chromium.org/p/chromium/issues/detail?id=924225</a></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Nov 19, 2018 at 8:40 AM Sam McCall via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: sammccall<br>
Date: Mon Nov 19 05:37:46 2018<br>
New Revision: 347205<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=347205&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=347205&view=rev</a><br>
Log:<br>
[FileManager] getFile(open=true) after getFile(open=false) should open the file.<br>
<br>
Summary:<br>
Old behavior is to just return the cached entry regardless of opened-ness.<br>
That feels buggy (though I guess nobody ever actually needed this).<br>
<br>
This came up in the context of clangd+clang-tidy integration: we're<br>
going to getFile(open=false) to replay preprocessor actions obscured by<br>
the preamble, but the compilation may subsequently getFile(open=true)<br>
for non-preamble includes.<br>
<br>
Reviewers: ilya-biryukov<br>
<br>
Subscribers: ioeric, kadircet, cfe-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D54691" rel="noreferrer" target="_blank">https://reviews.llvm.org/D54691</a><br>
<br>
Modified:<br>
cfe/trunk/include/clang/Basic/FileManager.h<br>
cfe/trunk/lib/Basic/FileManager.cpp<br>
cfe/trunk/unittests/Basic/FileManagerTest.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Basic/FileManager.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/FileManager.h?rev=347205&r1=347204&r2=347205&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/FileManager.h?rev=347205&r1=347204&r2=347205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/FileManager.h (original)<br>
+++ cfe/trunk/include/clang/Basic/FileManager.h Mon Nov 19 05:37:46 2018<br>
@@ -70,14 +70,15 @@ class FileEntry {<br>
bool IsNamedPipe;<br>
bool InPCH;<br>
bool IsValid; // Is this \c FileEntry initialized and valid?<br>
+ bool DeferredOpen; // Created by getFile(OpenFile=0); may open later.<br>
<br>
/// The open file, if it is owned by the \p FileEntry.<br>
mutable std::unique_ptr<llvm::vfs::File> File;<br>
<br>
public:<br>
FileEntry()<br>
- : UniqueID(0, 0), IsNamedPipe(false), InPCH(false), IsValid(false)<br>
- {}<br>
+ : UniqueID(0, 0), IsNamedPipe(false), InPCH(false), IsValid(false),<br>
+ DeferredOpen(false) {}<br>
<br>
FileEntry(const FileEntry &) = delete;<br>
FileEntry &operator=(const FileEntry &) = delete;<br>
<br>
Modified: cfe/trunk/lib/Basic/FileManager.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileManager.cpp?rev=347205&r1=347204&r2=347205&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileManager.cpp?rev=347205&r1=347204&r2=347205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Basic/FileManager.cpp (original)<br>
+++ cfe/trunk/lib/Basic/FileManager.cpp Mon Nov 19 05:37:46 2018<br>
@@ -221,15 +221,21 @@ const FileEntry *FileManager::getFile(St<br>
*SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first;<br>
<br>
// See if there is already an entry in the map.<br>
- if (NamedFileEnt.second)<br>
- return NamedFileEnt.second == NON_EXISTENT_FILE ? nullptr<br>
- : NamedFileEnt.second;<br>
+ if (NamedFileEnt.second) {<br>
+ if (NamedFileEnt.second == NON_EXISTENT_FILE)<br>
+ return nullptr;<br>
+ // Entry exists: return it *unless* it wasn't opened and open is requested.<br>
+ if (!(NamedFileEnt.second->DeferredOpen && openFile))<br>
+ return NamedFileEnt.second;<br>
+ // We previously stat()ed the file, but didn't open it: do that below.<br>
+ // FIXME: the below does other redundant work too (stats the dir and file).<br>
+ } else {<br>
+ // By default, initialize it to invalid.<br>
+ NamedFileEnt.second = NON_EXISTENT_FILE;<br>
+ }<br>
<br>
++NumFileCacheMisses;<br>
<br>
- // By default, initialize it to invalid.<br>
- NamedFileEnt.second = NON_EXISTENT_FILE;<br>
-<br>
// Get the null-terminated file name as stored as the key of the<br>
// SeenFileEntries map.<br>
StringRef InterndFileName = NamedFileEnt.first();<br>
@@ -267,6 +273,7 @@ const FileEntry *FileManager::getFile(St<br>
// It exists. See if we have already opened a file with the same inode.<br>
// This occurs when one dir is symlinked to another, for example.<br>
FileEntry &UFE = UniqueRealFiles[Data.UniqueID];<br>
+ UFE.DeferredOpen = !openFile;<br>
<br>
NamedFileEnt.second = &UFE;<br>
<br>
@@ -283,6 +290,23 @@ const FileEntry *FileManager::getFile(St<br>
InterndFileName = NamedFileEnt.first().data();<br>
}<br>
<br>
+ // If we opened the file for the first time, record the resulting info.<br>
+ // Do this even if the cache entry was valid, maybe we didn't previously open.<br>
+ if (F && !UFE.File) {<br>
+ if (auto PathName = F->getName()) {<br>
+ llvm::SmallString<128> AbsPath(*PathName);<br>
+ // This is not the same as `VFS::getRealPath()`, which resolves symlinks<br>
+ // but can be very expensive on real file systems.<br>
+ // FIXME: the semantic of RealPathName is unclear, and the name might be<br>
+ // misleading. We need to clean up the interface here.<br>
+ makeAbsolutePath(AbsPath);<br>
+ llvm::sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true);<br>
+ UFE.RealPathName = AbsPath.str();<br>
+ }<br>
+ UFE.File = std::move(F);<br>
+ assert(!UFE.DeferredOpen && "we just opened it!");<br>
+ }<br>
+<br>
if (UFE.isValid()) { // Already have an entry with this inode, return it.<br>
<br>
// FIXME: this hack ensures that if we look up a file by a virtual path in<br>
@@ -313,21 +337,9 @@ const FileEntry *FileManager::getFile(St<br>
UFE.UniqueID = Data.UniqueID;<br>
UFE.IsNamedPipe = Data.IsNamedPipe;<br>
UFE.InPCH = Data.InPCH;<br>
- UFE.File = std::move(F);<br>
UFE.IsValid = true;<br>
+ // Note File and DeferredOpen were initialized above.<br>
<br>
- if (UFE.File) {<br>
- if (auto PathName = UFE.File->getName()) {<br>
- llvm::SmallString<128> AbsPath(*PathName);<br>
- // This is not the same as `VFS::getRealPath()`, which resolves symlinks<br>
- // but can be very expensive on real file systems.<br>
- // FIXME: the semantic of RealPathName is unclear, and the name might be<br>
- // misleading. We need to clean up the interface here.<br>
- makeAbsolutePath(AbsPath);<br>
- llvm::sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true);<br>
- UFE.RealPathName = AbsPath.str();<br>
- }<br>
- }<br>
return &UFE;<br>
}<br>
<br>
@@ -398,6 +410,7 @@ FileManager::getVirtualFile(StringRef Fi<br>
UFE->UID = NextFileUID++;<br>
UFE->IsValid = true;<br>
UFE->File.reset();<br>
+ UFE->DeferredOpen = false;<br>
return UFE;<br>
}<br>
<br>
<br>
Modified: cfe/trunk/unittests/Basic/FileManagerTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Basic/FileManagerTest.cpp?rev=347205&r1=347204&r2=347205&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Basic/FileManagerTest.cpp?rev=347205&r1=347204&r2=347205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/unittests/Basic/FileManagerTest.cpp (original)<br>
+++ cfe/trunk/unittests/Basic/FileManagerTest.cpp Mon Nov 19 05:37:46 2018<br>
@@ -222,6 +222,33 @@ TEST_F(FileManagerTest, getFileReturnsNU<br>
EXPECT_EQ(nullptr, file);<br>
}<br>
<br>
+// When calling getFile(OpenFile=false); getFile(OpenFile=true) the file is<br>
+// opened for the second call.<br>
+TEST_F(FileManagerTest, getFileDefersOpen) {<br>
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(<br>
+ new llvm::vfs::InMemoryFileSystem());<br>
+ FS->addFile("/tmp/test", 0, llvm::MemoryBuffer::getMemBufferCopy("test"));<br>
+ FS->addFile("/tmp/testv", 0, llvm::MemoryBuffer::getMemBufferCopy("testv"));<br>
+ FileManager manager(options, FS);<br>
+<br>
+ const FileEntry *file = manager.getFile("/tmp/test", /*OpenFile=*/false);<br>
+ ASSERT_TRUE(file != nullptr);<br>
+ ASSERT_TRUE(file->isValid());<br>
+ // "real path name" reveals whether the file was actually opened.<br>
+ EXPECT_EQ("", file->tryGetRealPathName());<br>
+<br>
+ file = manager.getFile("/tmp/test", /*OpenFile=*/true);<br>
+ ASSERT_TRUE(file != nullptr);<br>
+ ASSERT_TRUE(file->isValid());<br>
+ EXPECT_EQ("/tmp/test", file->tryGetRealPathName());<br>
+<br>
+ // However we should never try to open a file previously opened as virtual.<br>
+ ASSERT_TRUE(manager.getVirtualFile("/tmp/testv", 5, 0));<br>
+ ASSERT_TRUE(manager.getFile("/tmp/testv", /*OpenFile=*/false));<br>
+ file = manager.getFile("/tmp/testv", /*OpenFile=*/true);<br>
+ EXPECT_EQ("", file->tryGetRealPathName());<br>
+}<br>
+<br>
// The following tests apply to Unix-like system only.<br>
<br>
#ifndef _WIN32<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>