forked from OSchip/llvm-project
[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 llvm-svn: 291644
This commit is contained in:
parent
e482403e1c
commit
ba1b5c98ba
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
#import "someheader.h"
|
||||
|
||||
typedef myint aint;
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
#import "someheader.h"
|
||||
|
||||
typedef myint bint;
|
|
@ -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 *
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef C_GUARD
|
||||
#define C_GUARD
|
||||
|
||||
typedef int myint;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
#import "someheader.h"
|
||||
|
||||
typedef myint aint;
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
#import "someheader.h"
|
||||
|
||||
typedef myint bint;
|
|
@ -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 *
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
typedef int myint;
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _LIBCPP_CSTDDEF
|
||||
#define _LIBCPP_CSTDDEF
|
||||
|
||||
#include <stddef.h>
|
||||
#include <type_traits>
|
||||
|
||||
typedef ptrdiff_t my_ptrdiff_t;
|
||||
|
||||
#endif
|
|
@ -4,4 +4,6 @@
|
|||
#include_next <math.h>
|
||||
template<typename T> T abs(T t) { return (t < 0) ? -t : t; }
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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 * }
|
||||
}
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
#define LIBCXX_STDDEF_H
|
||||
|
||||
#include <__config>
|
||||
#include_next <stddef.h>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _LIBCPP_TYPE_TRAITS
|
||||
#define _LIBCPP_TYPE_TRAITS
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#endif
|
|
@ -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 *
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,6 @@
|
|||
// stddef.h
|
||||
#ifndef __STDDEF_H__
|
||||
#define __STDDEF_H__
|
||||
|
||||
#include "sys/_types/_ptrdiff_t.h"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef _PTRDIFF_T
|
||||
#define _PTRDIFF_T
|
||||
typedef int * ptrdiff_t;
|
||||
#endif /* _PTRDIFF_T */
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _SYS_TYPES_UMBRELLA
|
||||
#define _SYS_TYPES_UMBRELLA
|
||||
|
||||
#include "_ptrdiff_t.h"
|
||||
|
||||
#endif
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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;
|
Loading…
Reference in New Issue