summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruno Cardoso Lopes <bruno.cardoso@gmail.com>2017-01-11 02:14:51 +0000
committerBruno Cardoso Lopes <bruno.cardoso@gmail.com>2017-01-11 02:14:51 +0000
commitc899dcdc84f5ceac62a6a8c8aa1cf9c323eef6eb (patch)
tree7a06f40e88425feff846f82290ab0e99decdf23c
parent0fd8210f95926898933e372b6646a3ea69f2cacb (diff)
[Modules] Support #import when entering files with modules
Textual headers and builtins that are #import'd from different modules should get re-entered when these modules are independent from each other. Differential Revision: https://reviews.llvm.org/D26267 rdar://problem/25881934 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@291644 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Lex/HeaderSearch.h3
-rw-r--r--include/clang/Lex/ModuleMap.h8
-rw-r--r--lib/Lex/HeaderSearch.cpp47
-rw-r--r--lib/Lex/ModuleMap.cpp6
-rw-r--r--lib/Lex/PPDirectives.cpp1
-rw-r--r--test/Modules/Inputs/import-textual/M/A/A.h4
-rw-r--r--test/Modules/Inputs/import-textual/M/B/B.h4
-rw-r--r--test/Modules/Inputs/import-textual/M/module.modulemap17
-rw-r--r--test/Modules/Inputs/import-textual/M/someheader.h6
-rw-r--r--test/Modules/Inputs/import-textual/M2/A/A.h4
-rw-r--r--test/Modules/Inputs/import-textual/M2/B/B.h4
-rw-r--r--test/Modules/Inputs/import-textual/M2/module.modulemap17
-rw-r--r--test/Modules/Inputs/import-textual/M2/someheader.h1
-rw-r--r--test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/cstddef9
-rw-r--r--test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/math.h2
-rw-r--r--test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/module.modulemap2
-rw-r--r--test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stddef.h1
-rw-r--r--test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/type_traits6
-rw-r--r--test/Modules/Inputs/libc-libcxx/sysroot/usr/include/module.modulemap8
-rw-r--r--test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stddef.h7
-rw-r--r--test/Modules/Inputs/libc-libcxx/sysroot/usr/include/sys/_types/_ptrdiff_t.h4
-rw-r--r--test/Modules/Inputs/libc-libcxx/sysroot/usr/include/sys/_types/_types.h6
-rw-r--r--test/Modules/builtin-import.mm12
-rw-r--r--test/Modules/import-textual-noguard.mm8
-rw-r--r--test/Modules/import-textual.mm10
25 files changed, 188 insertions, 9 deletions
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 4df3e78311..51983b9ab5 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -406,7 +406,8 @@ public:
/// \return false if \#including the file will have no effect or true
/// if we should include it.
bool ShouldEnterIncludeFile(Preprocessor &PP, const FileEntry *File,
- bool isImport, Module *CorrespondingModule);
+ bool isImport, bool ModulesEnabled,
+ Module *CorrespondingModule);
/// \brief Return whether the specified file is a normal header,
/// a system header, or a C++ friendly system header.
diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h
index b3a2421af8..46136725d8 100644
--- a/include/clang/Lex/ModuleMap.h
+++ b/include/clang/Lex/ModuleMap.h
@@ -316,6 +316,14 @@ public:
BuiltinIncludeDir = Dir;
}
+ /// \brief Get the directory that contains Clang-supplied include files.
+ const DirectoryEntry *getBuiltinDir() const {
+ return BuiltinIncludeDir;
+ }
+
+ /// \brief Is this a compiler builtin header?
+ static bool isBuiltinHeader(StringRef FileName);
+
/// \brief Add a module map callback.
void addModuleMapCallbacks(std::unique_ptr<ModuleMapCallbacks> Callback) {
Callbacks.push_back(std::move(Callback));
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index fa2a76ef47..c667f4bf22 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -1092,13 +1092,51 @@ void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
}
bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
- const FileEntry *File,
- bool isImport, Module *M) {
+ const FileEntry *File, bool isImport,
+ bool ModulesEnabled, Module *M) {
++NumIncluded; // Count # of attempted #includes.
// Get information about this file.
HeaderFileInfo &FileInfo = getFileInfo(File);
+ // FIXME: this is a workaround for the lack of proper modules-aware support
+ // for #import / #pragma once
+ auto TryEnterImported = [&](void) -> bool {
+ if (!ModulesEnabled)
+ return false;
+ // Modules with builtins are special; multiple modules use builtins as
+ // modular headers, example:
+ //
+ // module stddef { header "stddef.h" export * }
+ //
+ // After module map parsing, this expands to:
+ //
+ // module stddef {
+ // header "/path_to_builtin_dirs/stddef.h"
+ // textual "stddef.h"
+ // }
+ //
+ // It's common that libc++ and system modules will both define such
+ // submodules. Make sure cached results for a builtin header won't
+ // prevent other builtin modules to potentially enter the builtin header.
+ // Note that builtins are header guarded and the decision to actually
+ // enter them is postponed to the controlling macros logic below.
+ bool TryEnterHdr = false;
+ if (FileInfo.isCompilingModuleHeader && FileInfo.isModuleHeader)
+ TryEnterHdr = File->getDir() == ModMap.getBuiltinDir() &&
+ ModuleMap::isBuiltinHeader(
+ llvm::sys::path::filename(File->getName()));
+
+ // Textual headers can be #imported from different modules. Since ObjC
+ // headers find in the wild might rely only on #import and do not contain
+ // controlling macros, be conservative and only try to enter textual headers
+ // if such macro is present.
+ if (!FileInfo.isModuleHeader &&
+ FileInfo.getControllingMacro(ExternalLookup))
+ TryEnterHdr = true;
+ return TryEnterHdr;
+ };
+
// If this is a #import directive, check that we have not already imported
// this header.
if (isImport) {
@@ -1106,11 +1144,12 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
FileInfo.isImport = true;
// Has this already been #import'ed or #include'd?
- if (FileInfo.NumIncludes) return false;
+ if (FileInfo.NumIncludes && !TryEnterImported())
+ return false;
} else {
// Otherwise, if this is a #include of a file that was previously #import'd
// or if this is the second #include of a #pragma once file, ignore it.
- if (FileInfo.isImport)
+ if (FileInfo.isImport && !TryEnterImported())
return false;
}
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 9d0f2eb2fa..db834ede02 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -144,7 +144,7 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
/// \brief Determine whether the given file name is the name of a builtin
/// header, supplied by Clang to replace, override, or augment existing system
/// headers.
-static bool isBuiltinHeader(StringRef FileName) {
+bool ModuleMap::isBuiltinHeader(StringRef FileName) {
return llvm::StringSwitch<bool>(FileName)
.Case("float.h", true)
.Case("iso646.h", true)
@@ -165,7 +165,7 @@ ModuleMap::findKnownHeader(const FileEntry *File) {
HeadersMap::iterator Known = Headers.find(File);
if (HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&
Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
- isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
+ ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
HeaderInfo.loadTopLevelSystemModules();
return Headers.find(File);
}
@@ -1879,7 +1879,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
// supplied by Clang. Find that builtin header.
if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword &&
BuiltinIncludeDir && BuiltinIncludeDir != Directory &&
- isBuiltinHeader(Header.FileName)) {
+ ModuleMap::isBuiltinHeader(Header.FileName)) {
SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
llvm::sys::path::append(BuiltinPathName, Header.FileName);
BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 9661e7b13f..322c5809cd 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1999,6 +1999,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
bool SkipHeader = false;
if (ShouldEnter &&
!HeaderInfo.ShouldEnterIncludeFile(*this, File, isImport,
+ getLangOpts().Modules,
SuggestedModule.getModule())) {
ShouldEnter = false;
SkipHeader = true;
diff --git a/test/Modules/Inputs/import-textual/M/A/A.h b/test/Modules/Inputs/import-textual/M/A/A.h
new file mode 100644
index 0000000000..ebe4979d7c
--- /dev/null
+++ b/test/Modules/Inputs/import-textual/M/A/A.h
@@ -0,0 +1,4 @@
+
+#import "someheader.h"
+
+typedef myint aint;
diff --git a/test/Modules/Inputs/import-textual/M/B/B.h b/test/Modules/Inputs/import-textual/M/B/B.h
new file mode 100644
index 0000000000..ba85071c01
--- /dev/null
+++ b/test/Modules/Inputs/import-textual/M/B/B.h
@@ -0,0 +1,4 @@
+
+#import "someheader.h"
+
+typedef myint bint;
diff --git a/test/Modules/Inputs/import-textual/M/module.modulemap b/test/Modules/Inputs/import-textual/M/module.modulemap
new file mode 100644
index 0000000000..f80194876c
--- /dev/null
+++ b/test/Modules/Inputs/import-textual/M/module.modulemap
@@ -0,0 +1,17 @@
+
+module M {
+
+ module A {
+ header "A/A.h"
+ textual header "someheader.h"
+ export *
+ }
+
+ module B {
+ header "B/B.h"
+ textual header "someheader.h"
+ export *
+ }
+
+ export *
+}
diff --git a/test/Modules/Inputs/import-textual/M/someheader.h b/test/Modules/Inputs/import-textual/M/someheader.h
new file mode 100644
index 0000000000..16fae40872
--- /dev/null
+++ b/test/Modules/Inputs/import-textual/M/someheader.h
@@ -0,0 +1,6 @@
+#ifndef C_GUARD
+#define C_GUARD
+
+typedef int myint;
+
+#endif
diff --git a/test/Modules/Inputs/import-textual/M2/A/A.h b/test/Modules/Inputs/import-textual/M2/A/A.h
new file mode 100644
index 0000000000..ebe4979d7c
--- /dev/null
+++ b/test/Modules/Inputs/import-textual/M2/A/A.h
@@ -0,0 +1,4 @@
+
+#import "someheader.h"
+
+typedef myint aint;
diff --git a/test/Modules/Inputs/import-textual/M2/B/B.h b/test/Modules/Inputs/import-textual/M2/B/B.h
new file mode 100644
index 0000000000..ba85071c01
--- /dev/null
+++ b/test/Modules/Inputs/import-textual/M2/B/B.h
@@ -0,0 +1,4 @@
+
+#import "someheader.h"
+
+typedef myint bint;
diff --git a/test/Modules/Inputs/import-textual/M2/module.modulemap b/test/Modules/Inputs/import-textual/M2/module.modulemap
new file mode 100644
index 0000000000..f80194876c
--- /dev/null
+++ b/test/Modules/Inputs/import-textual/M2/module.modulemap
@@ -0,0 +1,17 @@
+
+module M {
+
+ module A {
+ header "A/A.h"
+ textual header "someheader.h"
+ export *
+ }
+
+ module B {
+ header "B/B.h"
+ textual header "someheader.h"
+ export *
+ }
+
+ export *
+}
diff --git a/test/Modules/Inputs/import-textual/M2/someheader.h b/test/Modules/Inputs/import-textual/M2/someheader.h
new file mode 100644
index 0000000000..df2009a019
--- /dev/null
+++ b/test/Modules/Inputs/import-textual/M2/someheader.h
@@ -0,0 +1 @@
+typedef int myint;
diff --git a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/cstddef b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/cstddef
new file mode 100644
index 0000000000..4898c05fdb
--- /dev/null
+++ b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/cstddef
@@ -0,0 +1,9 @@
+#ifndef _LIBCPP_CSTDDEF
+#define _LIBCPP_CSTDDEF
+
+#include <stddef.h>
+#include <type_traits>
+
+typedef ptrdiff_t my_ptrdiff_t;
+
+#endif
diff --git a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/math.h b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/math.h
index f761b910f3..9e2b693612 100644
--- a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/math.h
+++ b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/math.h
@@ -4,4 +4,6 @@
#include_next <math.h>
template<typename T> T abs(T t) { return (t < 0) ? -t : t; }
+#include <type_traits>
+
#endif
diff --git a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/module.modulemap b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/module.modulemap
index b06142a61a..f57c11c423 100644
--- a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/module.modulemap
+++ b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/module.modulemap
@@ -6,5 +6,7 @@ module "libc++" {
// FIXME: remove "textual" from stdint module below once the issue
// between umbrella headers and builtins is resolved.
module stdint { textual header "stdint.h" export * }
+ module type_traits { header "type_traits" export * }
+ module cstddef { header "cstddef" export * }
module __config { header "__config" export * }
}
diff --git a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stddef.h b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stddef.h
index bd42008e16..14167cfe1d 100644
--- a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stddef.h
+++ b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/stddef.h
@@ -2,5 +2,6 @@
#define LIBCXX_STDDEF_H
#include <__config>
+#include_next <stddef.h>
#endif
diff --git a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/type_traits b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/type_traits
new file mode 100644
index 0000000000..a91056e008
--- /dev/null
+++ b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/c++/v1/type_traits
@@ -0,0 +1,6 @@
+#ifndef _LIBCPP_TYPE_TRAITS
+#define _LIBCPP_TYPE_TRAITS
+
+#include <cstddef>
+
+#endif
diff --git a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/module.modulemap b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/module.modulemap
index 7244cb0987..25b9468d29 100644
--- a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/module.modulemap
+++ b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/module.modulemap
@@ -5,4 +5,12 @@ module libc [no_undeclared_includes] {
module stdint { header "stdint.h" export * }
module stdio { header "stdio.h" export * }
module util { header "util.h" export * }
+ module POSIX {
+ module sys {
+ module types {
+ umbrella header "sys/_types/_types.h"
+ export *
+ }
+ }
+ }
}
diff --git a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stddef.h b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stddef.h
index eca72412a6..b98249f086 100644
--- a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stddef.h
+++ b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/stddef.h
@@ -1 +1,6 @@
-// stddef.h
+#ifndef __STDDEF_H__
+#define __STDDEF_H__
+
+#include "sys/_types/_ptrdiff_t.h"
+
+#endif
diff --git a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/sys/_types/_ptrdiff_t.h b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/sys/_types/_ptrdiff_t.h
new file mode 100644
index 0000000000..d14110e464
--- /dev/null
+++ b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/sys/_types/_ptrdiff_t.h
@@ -0,0 +1,4 @@
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef int * ptrdiff_t;
+#endif /* _PTRDIFF_T */
diff --git a/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/sys/_types/_types.h b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/sys/_types/_types.h
new file mode 100644
index 0000000000..33d5e51443
--- /dev/null
+++ b/test/Modules/Inputs/libc-libcxx/sysroot/usr/include/sys/_types/_types.h
@@ -0,0 +1,6 @@
+#ifndef _SYS_TYPES_UMBRELLA
+#define _SYS_TYPES_UMBRELLA
+
+#include "_ptrdiff_t.h"
+
+#endif
diff --git a/test/Modules/builtin-import.mm b/test/Modules/builtin-import.mm
new file mode 100644
index 0000000000..2536ac51c4
--- /dev/null
+++ b/test/Modules/builtin-import.mm
@@ -0,0 +1,12 @@
+// REQUIRES: system-darwin
+
+// RUN: rm -rf %t
+// RUN: %clang -cc1 -fsyntax-only -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ -fmodules-local-submodule-visibility %s
+
+#include <stdio.h>
+#include <stddef.h>
+#include <cstddef>
+
+typedef ptrdiff_t try1_ptrdiff_t;
+typedef my_ptrdiff_t try2_ptrdiff_t;
+
diff --git a/test/Modules/import-textual-noguard.mm b/test/Modules/import-textual-noguard.mm
new file mode 100644
index 0000000000..dd124b6609
--- /dev/null
+++ b/test/Modules/import-textual-noguard.mm
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fmodules -fimplicit-module-maps -I%S/Inputs/import-textual/M2 -fmodules-cache-path=%t -x objective-c++ -fmodules-local-submodule-visibility %s -verify
+
+#include "A/A.h" // expected-error {{could not build module 'M'}}
+#include "B/B.h"
+
+typedef aint xxx;
+typedef bint yyy;
diff --git a/test/Modules/import-textual.mm b/test/Modules/import-textual.mm
new file mode 100644
index 0000000000..6593239d7f
--- /dev/null
+++ b/test/Modules/import-textual.mm
@@ -0,0 +1,10 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fmodules -fimplicit-module-maps -I%S/Inputs/import-textual/M -fmodules-cache-path=%t -x objective-c++ -fmodules-local-submodule-visibility %s -verify
+
+// expected-no-diagnostics
+
+#include "A/A.h"
+#include "B/B.h"
+
+typedef aint xxx;
+typedef bint yyy;