diff --git a/clang/test/VFS/Inputs/vfsoverlay-root-relative.yaml b/clang/test/VFS/Inputs/vfsoverlay-root-relative.yaml new file mode 100644 --- /dev/null +++ b/clang/test/VFS/Inputs/vfsoverlay-root-relative.yaml @@ -0,0 +1,17 @@ +{ + 'version': 0, + 'fallthrough': true, + 'overlay-relative': true, + 'roots': [ + { 'name': 'virtual', + 'type': 'directory', + 'contents': [ + { + 'external-contents': 'actual_header.h', + 'type': 'file', + 'name': 'virtual_header.h', + } + ] + } + ] +} diff --git a/clang/test/VFS/vfsoverlay-relative-root.c b/clang/test/VFS/vfsoverlay-relative-root.c new file mode 100644 --- /dev/null +++ b/clang/test/VFS/vfsoverlay-relative-root.c @@ -0,0 +1,3 @@ +// RUN: %clang_cc1 -Werror -ivfsoverlay %S/Inputs/vfsoverlay-root-relative.yaml -I virtual -fsyntax-only %s + +#include "virtual_header.h" diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -547,6 +547,9 @@ /// } /// \endverbatim /// +/// The roots may be absolute or relative. If relative they will be made +/// absolute against the current working directory. +/// /// All configuration options are optional. /// 'case-sensitive': /// 'use-external-names': diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -1649,10 +1649,19 @@ sys::path::Style::windows_backslash)) { path_style = sys::path::Style::windows_backslash; } else { - assert(NameValueNode && "Name presence should be checked earlier"); - error(NameValueNode, + // Relative VFS root entries are made absolute to the current working + // directory, then we can determine the path style from that. + auto EC = sys::fs::make_absolute(Name); + if (EC) { + assert(NameValueNode && "Name presence should be checked earlier"); + error( + NameValueNode, "entry with relative path at the root level is not discoverable"); - return nullptr; + return nullptr; + } + path_style = sys::path::is_absolute(Name, sys::path::Style::posix) + ? sys::path::Style::posix + : sys::path::Style::windows_backslash; } } diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -2164,6 +2164,11 @@ TEST_F(VFSFromYAMLTest, RelativePaths) { IntrusiveRefCntPtr Lower(new DummyFileSystem()); + std::error_code EC; + SmallString<128> current_dir; + EC = llvm::sys::fs::current_path(current_dir); + ASSERT_FALSE(EC); + // Filename at root level without a parent directory. IntrusiveRefCntPtr FS = getFromYAMLString( "{ 'roots': [\n" @@ -2172,7 +2177,12 @@ " }\n" "] }", Lower); - EXPECT_EQ(nullptr, FS.get()); + ASSERT_TRUE(FS.get() != nullptr); + SmallString<128> expected_path_not_in_dir("file-not-in-directory.h"); + llvm::sys::fs::make_absolute(expected_path_not_in_dir); + checkContents(FS->dir_begin(current_dir, EC), + {expected_path_not_in_dir}); + // Relative file path. FS = getFromYAMLString("{ 'roots': [\n" @@ -2181,7 +2191,13 @@ " }\n" "] }", Lower); - EXPECT_EQ(nullptr, FS.get()); + ASSERT_TRUE(FS.get() != nullptr); + SmallString<128> expected_path_relative_file_parent("relative/file"); + SmallString<128> expected_path_relative_file("relative/file/path.h"); + llvm::sys::fs::make_absolute(expected_path_relative_file_parent); + llvm::sys::fs::make_absolute(expected_path_relative_file); + checkContents(FS->dir_begin(expected_path_relative_file_parent, EC), + {expected_path_relative_file}); // Relative directory path. FS = getFromYAMLString( @@ -2191,9 +2207,15 @@ " }\n" "] }", Lower); - EXPECT_EQ(nullptr, FS.get()); + ASSERT_TRUE(FS.get() != nullptr); + SmallString<128> expected_path_relative_dir_parent("relative/directory"); + SmallString<128> expected_path_relative_dir("relative/directory/path.h"); + llvm::sys::fs::make_absolute(expected_path_relative_dir_parent); + llvm::sys::fs::make_absolute(expected_path_relative_dir); + checkContents(FS->dir_begin(expected_path_relative_dir_parent, EC), + {expected_path_relative_dir}); - EXPECT_EQ(3, NumDiagnostics); + EXPECT_EQ(0, NumDiagnostics); } TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {