diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -363,26 +363,26 @@ std::move(OverrideOptions), std::move(FS)); } -llvm::IntrusiveRefCntPtr -getVfsFromFile(const std::string &OverlayFile, - llvm::IntrusiveRefCntPtr BaseFS) { - llvm::ErrorOr> Buffer = - BaseFS->getBufferForFile(OverlayFile); - if (!Buffer) { - llvm::errs() << "Can't load virtual filesystem overlay file '" - << OverlayFile << "': " << Buffer.getError().message() - << ".\n"; - return nullptr; - } - - IntrusiveRefCntPtr FS = vfs::getVFSFromYAML( - std::move(Buffer.get()), /*DiagHandler*/ nullptr, OverlayFile); - if (!FS) { - llvm::errs() << "Error: invalid virtual filesystem overlay file '" - << OverlayFile << "'.\n"; +static IntrusiveRefCntPtr +getVFSFromFile(StringRef OverlayFile) { + if (OverlayFile.empty()) + return makeIntrusiveRefCnt( + vfs::getRealFileSystem()); + + auto OverlayFS = vfs::getVFSFromYAMLs(OverlayFile, vfs::getRealFileSystem()); + if (auto Err = OverlayFS.takeError()) { + handleAllErrors(std::move(Err), [](const FileError &FE) { + if (FE.convertToErrorCode() == std::errc::no_such_file_or_directory) { + errs() << "Can't load virtual filesystem overlay file '" + << FE.getFileName() << "': " << FE.message() << ".\n"; + } else { + errs() << "Error: invalid virtual filesystem overlay file '" + << FE.getFileName() << "'.\n"; + } + }); return nullptr; } - return FS; + return std::move(*OverlayFS); } int clangTidyMain(int argc, const char **argv) { @@ -400,16 +400,10 @@ return 1; } - llvm::IntrusiveRefCntPtr BaseFS( - new vfs::OverlayFileSystem(vfs::getRealFileSystem())); - - if (!VfsOverlay.empty()) { - IntrusiveRefCntPtr VfsFromFile = - getVfsFromFile(VfsOverlay, BaseFS); - if (!VfsFromFile) - return 1; - BaseFS->pushOverlay(std::move(VfsFromFile)); - } + llvm::IntrusiveRefCntPtr BaseFS = + getVFSFromFile(VfsOverlay); + if (!BaseFS) + return 1; auto OwningOptionsProvider = createOptionsProvider(BaseFS); auto *OptionsProvider = OwningOptionsProvider.get(); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4693,28 +4693,22 @@ clang::createVFSFromCompilerInvocation( const CompilerInvocation &CI, DiagnosticsEngine &Diags, IntrusiveRefCntPtr BaseFS) { - if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) + ArrayRef OptFiles = CI.getHeaderSearchOpts().VFSOverlayFiles; + if (OptFiles.empty()) return BaseFS; - IntrusiveRefCntPtr Result = BaseFS; - // earlier vfs files are on the bottom - for (const auto &File : CI.getHeaderSearchOpts().VFSOverlayFiles) { - llvm::ErrorOr> Buffer = - Result->getBufferForFile(File); - if (!Buffer) { - Diags.Report(diag::err_missing_vfs_overlay_file) << File; - continue; - } - - IntrusiveRefCntPtr FS = llvm::vfs::getVFSFromYAML( - std::move(Buffer.get()), /*DiagHandler*/ nullptr, File, - /*DiagContext*/ nullptr, Result); - if (!FS) { - Diags.Report(diag::err_invalid_vfs_overlay) << File; - continue; - } - - Result = FS; + SmallVector Files(OptFiles.begin(), OptFiles.end()); + Expected> OverlayFS = + llvm::vfs::getVFSFromYAMLs(Files, BaseFS); + if (auto Err = OverlayFS.takeError()) { + llvm::handleAllErrors(std::move(Err), [&](const llvm::FileError &FE) { + if (FE.convertToErrorCode() == std::errc::no_such_file_or_directory) { + Diags.Report(diag::err_missing_vfs_overlay_file) << FE.getFileName(); + } else { + Diags.Report(diag::err_invalid_vfs_overlay) << FE.getFileName(); + } + }); + return BaseFS; } - return Result; + return *OverlayFS; } diff --git a/clang/test/VFS/Inputs/vfsroot.yaml b/clang/test/VFS/Inputs/vfsroot.yaml --- a/clang/test/VFS/Inputs/vfsroot.yaml +++ b/clang/test/VFS/Inputs/vfsroot.yaml @@ -26,13 +26,6 @@ } ] }, - { 'name': '/indirect-vfs-root-files', 'type': 'directory', - 'contents': [ - { 'name': 'actual_header.h', 'type': 'file', - 'external-contents': 'TEST_DIR/Inputs/actual_header.h' - } - ] - }, { 'name': 'TEST_DIR/Inputs/Broken.framework', 'type': 'directory', 'contents': [ { 'name': 'Headers/A.h', 'type': 'file', diff --git a/clang/test/VFS/directory.c b/clang/test/VFS/directory.c --- a/clang/test/VFS/directory.c +++ b/clang/test/VFS/directory.c @@ -1,13 +1,11 @@ // RUN: rm -rf %t // RUN: mkdir -p %t/Underlying // RUN: mkdir -p %t/Overlay -// RUN: mkdir -p %t/Middle // RUN: echo '// B.h in Underlying' > %t/Underlying/B.h // RUN: echo '#ifdef NESTED' >> %t/Underlying/B.h // RUN: echo '#include "C.h"' >> %t/Underlying/B.h // RUN: echo '#endif' >> %t/Underlying/B.h // RUN: echo '// C.h in Underlying' > %t/Underlying/C.h -// RUN: echo '// C.h in Middle' > %t/Middle/C.h // RUN: echo '// C.h in Overlay' > %t/Overlay/C.h // 1) Underlying -> Overlay (C.h found, B.h falling back to Underlying) @@ -17,31 +15,11 @@ // RUN: sed -e "s@INPUT_DIR@Overlay@g" -e "s@OUT_DIR@%{/t:regex_replacement}/Underlying@g" %S/Inputs/vfsoverlay-directory-relative.yaml > %t/vfs-relative.yaml // RUN: %clang_cc1 -Werror -I %t/Underlying -ivfsoverlay %t/vfs-relative.yaml -fsyntax-only -E -C %s 2>&1 | FileCheck --check-prefix=DIRECT %s +// DIRECT: # 1 "{{.*(/|\\\\)Underlying(/|\\\\)}}B.h" // DIRECT: {{^}}// B.h in Underlying +// DIRECT: # 1 "{{.*(/|\\\\)Overlay(/|\\\\)}}C.h" // DIRECT: {{^}}// C.h in Overlay -// 2) Underlying -> Middle -> Overlay (C.h found, B.h falling back to Underlying) -// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}/Overlay@g" -e "s@OUT_DIR@%{/t:regex_replacement}/Middle@g" %S/Inputs/vfsoverlay-directory.yaml > %t/vfs.yaml -// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}/Middle@g" -e "s@OUT_DIR@%{/t:regex_replacement}/Underlying@g" %S/Inputs/vfsoverlay-directory.yaml > %t/vfs2.yaml -// RUN: %clang_cc1 -Werror -I %t/Underlying -ivfsoverlay %t/vfs.yaml -ivfsoverlay %t/vfs2.yaml -fsyntax-only -E -C %s 2>&1 | FileCheck --check-prefix=DIRECT %s -// RUN: %clang_cc1 -Werror -I %t/Underlying -ivfsoverlay %t/vfs.yaml -ivfsoverlay %t/vfs2.yaml -DNESTED -fsyntax-only -E -C %s 2>&1 | FileCheck --check-prefix=DIRECT %s - -// Same as direct above - -// 3) Underlying -> Middle -> Overlay (C.h falling back to Middle, B.h falling back to Underlying) -// RUN: rm -f %t/Overlay/C.h -// RUN: %clang_cc1 -Werror -I %t/Underlying -ivfsoverlay %t/vfs.yaml -ivfsoverlay %t/vfs2.yaml -fsyntax-only -E -C %s 2>&1 | FileCheck --check-prefix=FALLBACK %s - -// FALLBACK: {{^}}// B.h in Underlying -// FALLBACK: {{^}}// C.h in Middle - -// 3) Underlying -> Middle -> Overlay (C.h falling back to Underlying, B.h falling back to Underlying) -// RUN: rm -f %t/Middle/C.h -// RUN: %clang_cc1 -Werror -I %t/Underlying -ivfsoverlay %t/vfs.yaml -ivfsoverlay %t/vfs2.yaml -fsyntax-only -E -C %s 2>&1 | FileCheck --check-prefix=FALLBACK2 %s - -// FALLBACK2: {{^}}// B.h in Underlying -// FALLBACK2: {{^}}// C.h in Underlying - #include "B.h" #ifndef NESTED #include "C.h" diff --git a/clang/test/VFS/multiple-overlays.c b/clang/test/VFS/multiple-overlays.c new file mode 100644 --- /dev/null +++ b/clang/test/VFS/multiple-overlays.c @@ -0,0 +1,39 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s@EXTERNAL_DIR@%{/t:regex_replacement}/B@g" -e "s@NAME_DIR@%{/t:regex_replacement}/A@g" %t/vfs/base.yaml > %t/vfs/a-b.yaml +// RUN: sed -e "s@EXTERNAL_DIR@%{/t:regex_replacement}/C@g" -e "s@NAME_DIR@%{/t:regex_replacement}/B@g" %t/vfs/base.yaml > %t/vfs/b-c.yaml + +// Overlays should not be transitive, ie. given overlays of A -> B and B -> C, A should not remap to +// C. + +// RUN: %clang_cc1 -Werror -I %t/A -ivfsoverlay %t/vfs/b-c.yaml -ivfsoverlay %t/vfs/a-b.yaml -fsyntax-only -E -C %t/main.c 2>&1 | FileCheck --check-prefix=FROM_B %s +// FROM_B: # 1 "{{.*(/|\\\\)B(/|\\\\)}}Header.h" +// FROM_B: // Header.h in B + +// RUN: %clang_cc1 -Werror -I %t/B -ivfsoverlay %t/vfs/b-c.yaml -ivfsoverlay %t/vfs/a-b.yaml -fsyntax-only -E -C %t/main.c 2>&1 | FileCheck --check-prefix=FROM_C %s +// FROM_C: # 1 "{{.*(/|\\\\)C(/|\\\\)}}Header.h" +// FROM_C: // Header.h in C + +//--- main.c +#include "Header.h" + +//--- A/Header.h +// Header.h in A + +//--- B/Header.h +// Header.h in B + +//--- C/Header.h +// Header.h in C + +//--- vfs/base.yaml +{ + 'version': 0, + 'redirecting-with': 'fallthrough', + 'roots': [ + { 'name': 'NAME_DIR', + 'type': 'directory-remap', + 'external-contents': 'EXTERNAL_DIR' + } + ] +} diff --git a/clang/test/VFS/vfsroot-with-overlay.c b/clang/test/VFS/vfsroot-with-overlay.c --- a/clang/test/VFS/vfsroot-with-overlay.c +++ b/clang/test/VFS/vfsroot-with-overlay.c @@ -1,7 +1,7 @@ // RUN: rm -rf %t // RUN: mkdir -p %t // RUN: sed -e "s@TEST_DIR@%{/S:regex_replacement}@g" -e "s@OUT_DIR@%{/t:regex_replacement}@g" %S/Inputs/vfsroot.yaml > %t.yaml -// RUN: sed -e "s@INPUT_DIR@/indirect-vfs-root-files@g" -e "s@OUT_DIR@/overlay-dir@g" %S/Inputs/vfsoverlay.yaml > %t/vfsoverlay.yaml +// RUN: sed -e "s@INPUT_DIR@%{/S:regex_replacement}/Inputs@g" -e "s@OUT_DIR@/overlay-dir@g" %S/Inputs/vfsoverlay.yaml > %t/vfsoverlay.yaml // RUN: %clang_cc1 -Werror -ivfsoverlay %t.yaml -ivfsoverlay /direct-vfs-root-files/vfsoverlay.yaml -I /overlay-dir -fsyntax-only /tests/vfsroot-with-overlay.c #include "not_real.h" diff --git a/lldb/source/Commands/CommandObjectReproducer.cpp b/lldb/source/Commands/CommandObjectReproducer.cpp --- a/lldb/source/Commands/CommandObjectReproducer.cpp +++ b/lldb/source/Commands/CommandObjectReproducer.cpp @@ -409,23 +409,19 @@ switch (m_options.provider) { case eReproducerProviderFiles: { FileSpec vfs_mapping = loader->GetFile(); + std::string overlay_path = vfs_mapping.GetPath(); - // Read the VFS mapping. - ErrorOr> buffer = - vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath()); - if (!buffer) { - SetError(result, errorCodeToError(buffer.getError())); + Expected> vfs = + vfs::getVFSFromYAMLs(StringRef(overlay_path)); + if (auto err = vfs.takeError()) { + SetError(result, std::move(err)); return false; } - // Initialize a VFS from the given mapping. - IntrusiveRefCntPtr vfs = vfs::getVFSFromYAML( - std::move(buffer.get()), nullptr, vfs_mapping.GetPath()); - // Dump the VFS to a buffer. std::string str; raw_string_ostream os(str); - static_cast(*vfs).dump(os); + (*vfs)->dump(os); os.flush(); // Return the string. diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h --- a/llvm/include/llvm/Support/Error.h +++ b/llvm/include/llvm/Support/Error.h @@ -1281,7 +1281,7 @@ return OS.str(); } - StringRef getFileName() { return FileName; } + StringRef getFileName() const { return FileName; } Error takeError() { return Error(std::move(Err)); } diff --git a/llvm/tools/dsymutil/Reproducer.h b/llvm/tools/dsymutil/Reproducer.h --- a/llvm/tools/dsymutil/Reproducer.h +++ b/llvm/tools/dsymutil/Reproducer.h @@ -59,8 +59,7 @@ }; /// Reproducer instance used to use an existing reproducer. The VFS returned by -/// this instance is a RedirectingFileSystem that remaps paths to their -/// counterpart in the reproducer. +/// this instance remaps paths to their counterpart in the reproducer. class ReproducerUse : public Reproducer { public: ReproducerUse(StringRef Root, std::error_code &EC); diff --git a/llvm/tools/dsymutil/Reproducer.cpp b/llvm/tools/dsymutil/Reproducer.cpp --- a/llvm/tools/dsymutil/Reproducer.cpp +++ b/llvm/tools/dsymutil/Reproducer.cpp @@ -48,15 +48,15 @@ ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) { SmallString<128> Mapping(Root); sys::path::append(Mapping, "mapping.yaml"); - ErrorOr> Buffer = - vfs::getRealFileSystem()->getBufferForFile(Mapping.str()); - if (!Buffer) { - EC = Buffer.getError(); + auto OverlayFS = llvm::vfs::getVFSFromYAMLs(Mapping.str()); + if (auto Err = OverlayFS.takeError()) { + llvm::handleAllErrors(std::move(Err), [&](const llvm::ErrorInfoBase &E) { + EC = E.convertToErrorCode(); + }); return; } - - VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping); + VFS = std::move(*OverlayFS); } llvm::Expected>