summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/FileSystemStatCache.h4
-rw-r--r--clang/include/clang/Basic/VirtualFileSystem.h3
-rw-r--r--clang/lib/Basic/FileManager.cpp10
-rw-r--r--clang/lib/Basic/FileSystemStatCache.cpp1
-rw-r--r--clang/lib/Basic/VirtualFileSystem.cpp6
-rw-r--r--clang/test/VFS/Inputs/actual_module.map4
-rw-r--r--clang/test/VFS/Inputs/import_some_frame.h2
-rw-r--r--clang/test/VFS/Inputs/public_header.h1
-rw-r--r--clang/test/VFS/Inputs/public_header2.h1
-rw-r--r--clang/test/VFS/Inputs/some_frame_module.map5
-rw-r--r--clang/test/VFS/Inputs/vfsoverlay.yaml16
-rw-r--r--clang/test/VFS/real-path-found-first.m74
12 files changed, 123 insertions, 4 deletions
diff --git a/clang/include/clang/Basic/FileSystemStatCache.h b/clang/include/clang/Basic/FileSystemStatCache.h
index 2e9528db915..af2535661e5 100644
--- a/clang/include/clang/Basic/FileSystemStatCache.h
+++ b/clang/include/clang/Basic/FileSystemStatCache.h
@@ -38,6 +38,10 @@ struct FileData {
bool IsDirectory;
bool IsNamedPipe;
bool InPCH;
+ bool IsVFSMapped; // FIXME: remove this when files support multiple names
+ FileData()
+ : Size(0), ModTime(0), IsDirectory(false), IsNamedPipe(false),
+ InPCH(false), IsVFSMapped(false) {}
};
/// \brief Abstract interface for introducing a FileManager cache for 'stat'
diff --git a/clang/include/clang/Basic/VirtualFileSystem.h b/clang/include/clang/Basic/VirtualFileSystem.h
index 978e0408daf..0a9949612c0 100644
--- a/clang/include/clang/Basic/VirtualFileSystem.h
+++ b/clang/include/clang/Basic/VirtualFileSystem.h
@@ -40,6 +40,9 @@ class Status {
llvm::sys::fs::perms Perms;
public:
+ bool IsVFSMapped; // FIXME: remove when files support multiple names
+
+public:
Status() : Type(llvm::sys::fs::file_type::status_error) {}
Status(const llvm::sys::fs::file_status &Status);
Status(StringRef Name, StringRef RealName, llvm::sys::fs::UniqueID UID,
diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp
index 940fcaf4174..14731f6b09c 100644
--- a/clang/lib/Basic/FileManager.cpp
+++ b/clang/lib/Basic/FileManager.cpp
@@ -274,6 +274,16 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
NamedFileEnt.setValue(&UFE);
if (UFE.isValid()) { // Already have an entry with this inode, return it.
+
+ // FIXME: this hack ensures that if we look up a file by a virtual path in
+ // the VFS that the getDir() will have the virtual path, even if we found
+ // the file by a 'real' path first. This is required in order to find a
+ // module's structure when its headers/module map are mapped in the VFS.
+ // We should remove this as soon as we can properly support a file having
+ // multiple names.
+ if (DirInfo != UFE.Dir && Data.IsVFSMapped)
+ UFE.Dir = DirInfo;
+
// If the stat process opened the file, close it to avoid a FD leak.
if (F)
delete F;
diff --git a/clang/lib/Basic/FileSystemStatCache.cpp b/clang/lib/Basic/FileSystemStatCache.cpp
index 44ba48aa2fc..0f16e94a05e 100644
--- a/clang/lib/Basic/FileSystemStatCache.cpp
+++ b/clang/lib/Basic/FileSystemStatCache.cpp
@@ -39,6 +39,7 @@ static void copyStatusToFileData(const vfs::Status &Status,
Data.IsDirectory = Status.isDirectory();
Data.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
Data.InPCH = false;
+ Data.IsVFSMapped = Status.IsVFSMapped;
}
/// FileSystemStatCache::get - Get the 'stat' information for the specified
diff --git a/clang/lib/Basic/VirtualFileSystem.cpp b/clang/lib/Basic/VirtualFileSystem.cpp
index c89b071a773..a469c9abc39 100644
--- a/clang/lib/Basic/VirtualFileSystem.cpp
+++ b/clang/lib/Basic/VirtualFileSystem.cpp
@@ -31,13 +31,13 @@ using llvm::sys::fs::UniqueID;
Status::Status(const file_status &Status)
: UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
- Type(Status.type()), Perms(Status.permissions()) {}
+ Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false) {}
Status::Status(StringRef Name, StringRef ExternalName, UniqueID UID,
sys::TimeValue MTime, uint32_t User, uint32_t Group,
uint64_t Size, file_type Type, perms Perms)
: Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size),
- Type(Type), Perms(Perms) {}
+ Type(Type), Perms(Perms), IsVFSMapped(false) {}
bool Status::equivalent(const Status &Other) const {
return getUniqueID() == Other.getUniqueID();
@@ -801,6 +801,8 @@ ErrorOr<Status> VFSFromYAML::status(const Twine &Path) {
assert(!S || S->getName() == F->getExternalContentsPath());
if (S && !F->useExternalName(UseExternalNames))
S->setName(PathStr);
+ if (S)
+ S->IsVFSMapped = true;
return S;
} else { // directory
DirectoryEntry *DE = cast<DirectoryEntry>(*Result);
diff --git a/clang/test/VFS/Inputs/actual_module.map b/clang/test/VFS/Inputs/actual_module.map
index 282dac37c7b..d2f5b64a38d 100644
--- a/clang/test/VFS/Inputs/actual_module.map
+++ b/clang/test/VFS/Inputs/actual_module.map
@@ -2,3 +2,7 @@ module not_real {
header "not_real.h"
export *
}
+module import_some_frame {
+ header "import_some_frame.h"
+ export *
+}
diff --git a/clang/test/VFS/Inputs/import_some_frame.h b/clang/test/VFS/Inputs/import_some_frame.h
new file mode 100644
index 00000000000..c1f68c83fc5
--- /dev/null
+++ b/clang/test/VFS/Inputs/import_some_frame.h
@@ -0,0 +1,2 @@
+#import <SomeFramework/public_header.h>
+#import <SomeFramework/public_header2.h>
diff --git a/clang/test/VFS/Inputs/public_header.h b/clang/test/VFS/Inputs/public_header.h
index 471107762b1..09d9969d319 100644
--- a/clang/test/VFS/Inputs/public_header.h
+++ b/clang/test/VFS/Inputs/public_header.h
@@ -1 +1,2 @@
+#import <SomeFramework/public_header2.h>
void from_framework(void);
diff --git a/clang/test/VFS/Inputs/public_header2.h b/clang/test/VFS/Inputs/public_header2.h
new file mode 100644
index 00000000000..d883613ac12
--- /dev/null
+++ b/clang/test/VFS/Inputs/public_header2.h
@@ -0,0 +1 @@
+// public_header2.h
diff --git a/clang/test/VFS/Inputs/some_frame_module.map b/clang/test/VFS/Inputs/some_frame_module.map
new file mode 100644
index 00000000000..3ce59b254d8
--- /dev/null
+++ b/clang/test/VFS/Inputs/some_frame_module.map
@@ -0,0 +1,5 @@
+framework module SomeFramework {
+ umbrella header "public_header.h"
+ export *
+ module * { export * }
+}
diff --git a/clang/test/VFS/Inputs/vfsoverlay.yaml b/clang/test/VFS/Inputs/vfsoverlay.yaml
index 5c1380870d5..0aa8cd619a5 100644
--- a/clang/test/VFS/Inputs/vfsoverlay.yaml
+++ b/clang/test/VFS/Inputs/vfsoverlay.yaml
@@ -6,14 +6,26 @@
{ 'name': 'not_real.h', 'type': 'file',
'external-contents': 'INPUT_DIR/actual_header.h'
},
+ { 'name': 'import_some_frame.h', 'type': 'file',
+ 'external-contents': 'INPUT_DIR/import_some_frame.h'
+ },
{ 'name': 'module.map', 'type': 'file',
'external-contents': 'INPUT_DIR/actual_module.map'
},
{ 'name': 'include_real.h', 'type': 'file',
'external-contents': 'INPUT_DIR/include_real.h'
},
- { 'name': 'SomeFramework.framework/Headers/public_header.h', 'type': 'file',
- 'external-contents': 'INPUT_DIR/public_header.h'
+ { 'name': 'SomeFramework.framework', 'type': 'directory',
+ 'contents': [
+ { 'name': 'Headers', 'type': 'directory',
+ 'contents': [
+ { 'name': 'public_header.h', 'type': 'file',
+ 'external-contents': 'INPUT_DIR/public_header.h' },
+ { 'name': 'public_header2.h', 'type': 'file',
+ 'external-contents': 'INPUT_DIR/public_header2.h' }
+ ]
+ }
+ ]
},
{ 'name': 'Foo.framework/Headers/Foo.h', 'type': 'file',
'external-contents': 'INPUT_DIR/Foo.h'
diff --git a/clang/test/VFS/real-path-found-first.m b/clang/test/VFS/real-path-found-first.m
new file mode 100644
index 00000000000..f494c6eb153
--- /dev/null
+++ b/clang/test/VFS/real-path-found-first.m
@@ -0,0 +1,74 @@
+// This test is for cases where we lookup a file by its 'real' path before we
+// use its VFS-mapped path. If we accidentally use the real path in header
+// search, we will not find a module for the headers. To test that we
+// intentionally rebuild modules, since the precompiled module file refers to
+// the dependency files by real path.
+
+// REQUIRES: shell
+// RUN: rm -rf %t %t-cache %t.pch
+// RUN: mkdir -p %t/SomeFramework.framework/Modules
+// RUN: cp %S/Inputs/some_frame_module.map %t/SomeFramework.framework/Modules/module.modulemap
+// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml
+
+// Build
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t-cache -F %t \
+// RUN: -ivfsoverlay %t.yaml -fsyntax-only %s -verify -Wauto-import \
+// RUN: -Werror=non-modular-include-in-framework-module
+
+// Rebuild
+// RUN: echo ' ' >> %t/SomeFramework.framework/Modules/module.modulemap
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t-cache -F %t \
+// RUN: -ivfsoverlay %t.yaml -fsyntax-only %s -verify -Wauto-import \
+// RUN: -Werror=non-modular-include-in-framework-module
+
+// Load from PCH
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t-cache -F %t \
+// RUN: -ivfsoverlay %t.yaml -emit-pch %s -o %t.pch \
+// RUN: -Werror=non-modular-include-in-framework-module \
+// RUN: -fmodules-ignore-macro=WITH_PREFIX
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t-cache -F %t \
+// RUN: -ivfsoverlay %t.yaml -include-pch %t.pch -fsyntax-only %s \
+// RUN: -Werror=non-modular-include-in-framework-module -DWITH_PREFIX \
+// RUN: -fmodules-ignore-macro=WITH_PREFIX
+
+// While indexing
+// RUN: c-index-test -index-file %s -fmodules -fmodules-cache-path=%t-cache -F %t \
+// RUN: -ivfsoverlay %t.yaml -fsyntax-only -Wauto-import \
+// RUN: -Werror=non-modular-include-in-framework-module | FileCheck %s
+// RUN: echo ' ' >> %t/SomeFramework.framework/Modules/module.modulemap
+// RUN: c-index-test -index-file %s -fmodules -fmodules-cache-path=%t-cache -F %t \
+// RUN: -ivfsoverlay %t.yaml -fsyntax-only -Wauto-import \
+// RUN: -Werror=non-modular-include-in-framework-module | FileCheck %s
+// CHECK: warning: treating
+// CHECK-NOT: error
+
+// With a VFS-mapped module map file
+// RUN: mv %t/SomeFramework.framework/Modules/module.modulemap %t/hide_module.map
+// RUN: echo "{ 'version': 0, 'roots': [ { " > %t2.yaml
+// RUN: echo "'name': '%t/SomeFramework.framework/Modules/module.modulemap'," >> %t2.yaml
+// RUN: echo "'type': 'file', 'external-contents': '%t/hide_module.map' } ] }" >> %t2.yaml
+
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t-cache -F %t \
+// RUN: -ivfsoverlay %t.yaml -ivfsoverlay %t2.yaml -fsyntax-only %s -verify \
+// RUN: -Wauto-import -Werror=non-modular-include-in-framework-module
+// RUN: echo ' ' >> %t/hide_module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t-cache -F %t \
+// RUN: -ivfsoverlay %t.yaml -ivfsoverlay %t2.yaml -fsyntax-only %s -verify \
+// RUN: -Wauto-import -Werror=non-modular-include-in-framework-module
+
+// Within a module build
+// RUN: echo '@import import_some_frame;' | \
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t-cache -F %t \
+// RUN: -ivfsoverlay %t.yaml -ivfsoverlay %t2.yaml -fsyntax-only - \
+// RUN: -Werror=non-modular-include-in-framework-module -x objective-c -I %t
+// RUN: echo ' ' >> %t/hide_module.map
+// RUN: echo '@import import_some_frame;' | \
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t-cache -F %t \
+// RUN: -ivfsoverlay %t.yaml -ivfsoverlay %t2.yaml -fsyntax-only - \
+// RUN: -Werror=non-modular-include-in-framework-module -x objective-c -I %t
+
+#ifndef WITH_PREFIX
+#import <SomeFramework/public_header.h> // expected-warning{{treating}}
+#import <SomeFramework/public_header2.h> // expected-warning{{treating}}
+@import SomeFramework.public_header2;
+#endif
OpenPOWER on IntegriCloud