Back out my heinous hack that tricked the module generation mechanism

into using non-absolute system includes (<foo>)...

... and introduce another hack that is simultaneously more heineous
and more effective. We whitelist Clang-supplied headers that augment
or override system headers (such as float.h, stdarg.h, and
tgmath.h). For these headers, Clang does not provide a module
mapping. Instead, a system-supplied module map can refer to these
headers in a system module, and Clang will look both in its own
include directory and wherever the system-supplied module map
suggests, then adds either or both headers. The end result is that
Clang-supplied headers get merged into the system-supplied module for
the C standard library.

As a drive-by, fix up a few dependencies in the _Builtin_instrinsics
module.

llvm-svn: 149611
This commit is contained in:
Douglas Gregor 2012-02-02 18:42:48 +00:00
parent 248bc72737
commit 3ec6663be0
12 changed files with 160 additions and 106 deletions

View File

@ -41,6 +41,10 @@ class ModuleMap {
const LangOptions &LangOpts;
const TargetInfo *Target;
/// \brief The directory used for Clang-supplied, builtin include headers,
/// such as "stdint.h".
const DirectoryEntry *BuiltinIncludeDir;
/// \brief Language options used to parse the module map itself.
///
/// These are always simple C language options.
@ -102,6 +106,12 @@ public:
/// \brief Set the target information.
void setTarget(const TargetInfo &Target);
/// \brief Set the directory that contains Clang-supplied include
/// files, such as our stdarg.h or tgmath.h.
void setBuiltinIncludeDir(const DirectoryEntry *Dir) {
BuiltinIncludeDir = Dir;
}
/// \brief Retrieve the module that owns the given header file, if any.
///
/// \param File The header file that is likely to be included.

View File

@ -32,6 +32,8 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
if (Parent) {
if (!Parent->isAvailable())
IsAvailable = false;
if (Parent->IsSystem)
IsSystem = true;
Parent->SubModuleIndex[Name] = Parent->SubModules.size();
Parent->SubModules.push_back(this);

View File

@ -126,32 +126,6 @@ ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
Sysroot, OS);
}
/// \brief Add an appropriate #include/#import for the given header within
/// the current module context.
static void addHeaderInclude(StringRef Header,
bool IsBuiltinModule,
const LangOptions &LangOpts,
llvm::SmallString<256> &Includes) {
if (IsBuiltinModule) {
// Our own builtin headers play some evil tricks that depend both on
// knowing that our headers will be found first and on include_next. To
// Make sure these include_next tricks work, we include with <> and
// just the filename itself rather than using an absolutely path.
// FIXME: Is there some sensible way to generalize this?
Includes += "#include <";
Includes += llvm::sys::path::filename(Header);
Includes += ">\n";
return;
}
if (LangOpts.ObjC1)
Includes += "#import \"";
else
Includes += "#include \"";
Includes += Header;
Includes += "\"\n";
}
/// \brief Collect the set of header includes needed to construct the given
/// module.
///
@ -163,21 +137,31 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
FileManager &FileMgr,
ModuleMap &ModMap,
clang::Module *Module,
bool IsBuiltinModule,
llvm::SmallString<256> &Includes) {
// Don't collect any headers for unavailable modules.
if (!Module->isAvailable())
return;
// Add includes for each of these headers.
for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I)
addHeaderInclude(Module->Headers[I]->getName(), IsBuiltinModule, LangOpts,
Includes);
for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
if (LangOpts.ObjC1)
Includes += "#import \"";
else
Includes += "#include \"";
Includes += Module->Headers[I]->getName();
Includes += "\"\n";
}
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
if (Module->Parent)
addHeaderInclude(UmbrellaHeader->getName(), IsBuiltinModule, LangOpts,
Includes);
if (Module->Parent) {
// Include the umbrella header for submodules.
if (LangOpts.ObjC1)
Includes += "#import \"";
else
Includes += "#include \"";
Includes += UmbrellaHeader->getName();
Includes += "\"\n";
}
} else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) {
// Add all of the headers we find in this subdirectory.
llvm::error_code EC;
@ -199,8 +183,13 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
if (ModMap.isHeaderInUnavailableModule(Header))
continue;
// Include this header.
addHeaderInclude(Dir->path(), IsBuiltinModule, LangOpts, Includes);
// Include this header umbrella header for submodules.
if (LangOpts.ObjC1)
Includes += "#import \"";
else
Includes += "#include \"";
Includes += Dir->path();
Includes += "\"\n";
}
}
@ -208,8 +197,7 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
SubEnd = Module->submodule_end();
Sub != SubEnd; ++Sub)
collectModuleHeaderIncludes(LangOpts, FileMgr, ModMap, *Sub,
IsBuiltinModule, Includes);
collectModuleHeaderIncludes(LangOpts, FileMgr, ModMap, *Sub, Includes);
}
bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
@ -261,11 +249,10 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader();
// Collect the set of #includes we need to build the module.
bool IsBuiltinModule = StringRef(Module->Name).startswith("_Builtin_");
llvm::SmallString<256> HeaderContents;
collectModuleHeaderIncludes(CI.getLangOpts(), CI.getFileManager(),
CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
Module, IsBuiltinModule, HeaderContents);
Module, HeaderContents);
if (UmbrellaHeader && HeaderContents.empty()) {
// Simple case: we have an umbrella header and there are no additional
// includes, we can just parse the umbrella header directly.

View File

@ -666,5 +666,13 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
Init.AddDefaultIncludePaths(Lang, Triple, HSOpts);
if (HSOpts.UseBuiltinIncludes) {
// Set up the builtin include directory in the module map.
llvm::sys::Path P(HSOpts.ResourceDir);
P.appendComponent("include");
if (const DirectoryEntry *Dir = HS.getFileMgr().getDirectory(P.str()))
HS.getModuleMap().setBuiltinIncludeDir(Dir);
}
Init.Realize(Lang);
}

View File

@ -1,42 +1,3 @@
module _Builtin_stdlib [system] {
explicit module float_constants {
header "float.h"
}
explicit module iso646 {
header "iso646.h"
}
explicit module limits {
header "limits.h"
}
explicit module stdalign {
header "stdalign.h"
}
explicit module stdarg {
header "stdarg.h"
}
explicit module stdbool {
header "stdbool.h"
}
explicit module stddef {
header "stddef.h"
}
explicit module stdint {
header "stdint.h"
}
explicit module varargs {
requires unavailable
header "varargs.h"
}
}
module _Builtin_intrinsics [system] {
explicit module altivec {
requires altivec
@ -45,10 +6,16 @@ module _Builtin_intrinsics [system] {
explicit module intel {
requires x86
export *
header "immintrin.h"
header "x86intrin.h"
explicit module mm_malloc {
header "mm_malloc.h"
export * // note: for <stdlib.h> dependency
}
explicit module cpuid {
header "cpuid.h"
}
@ -61,6 +28,7 @@ module _Builtin_intrinsics [system] {
explicit module sse {
requires sse
export mmx
export * // note: for hackish <emmintrin.h> dependency
header "xmmintrin.h"
}
@ -136,12 +104,5 @@ module _Builtin_intrinsics [system] {
requires mm3dnow
header "mm3dnow.h"
}
explicit module mm_malloc {
header "mm_malloc.h"
}
}
// FIXME: tgmath.h
// FIXME: unwind.h
}

View File

@ -71,7 +71,7 @@ ModuleMap::resolveExport(Module *Mod,
ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
const LangOptions &LangOpts, const TargetInfo *Target)
: LangOpts(LangOpts), Target(Target)
: LangOpts(LangOpts), Target(Target), BuiltinIncludeDir(0)
{
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
Diags = llvm::IntrusiveRefCntPtr<DiagnosticsEngine>(
@ -499,7 +499,10 @@ namespace clang {
/// \brief The directory that this module map resides in.
const DirectoryEntry *Directory;
/// \brief The directory containing Clang-supplied headers.
const DirectoryEntry *BuiltinIncludeDir;
/// \brief Whether an error occurred.
bool HadError;
@ -540,9 +543,11 @@ namespace clang {
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
DiagnosticsEngine &Diags,
ModuleMap &Map,
const DirectoryEntry *Directory)
const DirectoryEntry *Directory,
const DirectoryEntry *BuiltinIncludeDir)
: L(L), SourceMgr(SourceMgr), Diags(Diags), Map(Map),
Directory(Directory), HadError(false), ActiveModule(0)
Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir),
HadError(false), ActiveModule(0)
{
TargetOptions TargetOpts;
TargetOpts.Triple = llvm::sys::getDefaultTargetTriple();
@ -1028,6 +1033,24 @@ void appendSubframeworkPaths(Module *Mod, llvm::SmallVectorImpl<char> &Path) {
}
}
/// \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) {
return llvm::StringSwitch<bool>(FileName)
.Case("float.h", true)
.Case("iso646.h", true)
.Case("limits.h", true)
.Case("stdalign.h", true)
.Case("stdarg.h", true)
.Case("stdbool.h", true)
.Case("stddef.h", true)
.Case("stdint.h", true)
.Case("tgmath.h", true)
.Case("unwind.h", true)
.Default(false);
}
/// \brief Parse a header declaration.
///
/// header-declaration:
@ -1058,6 +1081,7 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
// Look for this file.
const FileEntry *File = 0;
const FileEntry *BuiltinFile = 0;
llvm::SmallString<128> PathName;
if (llvm::sys::path::is_absolute(FileName)) {
PathName = FileName;
@ -1090,6 +1114,24 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
// Lookup for normal headers.
llvm::sys::path::append(PathName, FileName);
File = SourceMgr.getFileManager().getFile(PathName);
// If this is a system module with a top-level header, this header
// may have a counterpart (or replacement) in the set of headers
// supplied by Clang. Find that builtin header.
if (ActiveModule->IsSystem && !Umbrella && BuiltinIncludeDir &&
BuiltinIncludeDir != Directory && isBuiltinHeader(FileName)) {
llvm::SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
llvm::sys::path::append(BuiltinPathName, FileName);
BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
// If Clang supplies this header but the underlying system does not,
// just silently swap in our builtin version. Otherwise, we'll end
// up adding both (later).
if (!File && BuiltinFile) {
File = BuiltinFile;
BuiltinFile = 0;
}
}
}
}
@ -1113,6 +1155,10 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
} else {
// Record this header.
Map.addHeader(ActiveModule, File);
// If there is a builtin counterpart to this file, add it now.
if (BuiltinFile)
Map.addHeader(ActiveModule, BuiltinFile);
}
} else {
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
@ -1375,7 +1421,8 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
// Parse this module map file.
Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
Diags->getClient()->BeginSourceFile(MMapLangOpts);
ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir());
ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir(),
BuiltinIncludeDir);
bool Result = Parser.parseModuleMapFile();
Diags->getClient()->EndSourceFile();

View File

@ -0,0 +1,21 @@
module cstd [system] {
// Only in compiler support directory
module float_constants {
header "float.h"
}
// Only in system headers directory
module stdio {
header "stdio.h"
}
// In both directories (compiler support version wins, does not forward)
module stdbool {
header "stdbool.h"
}
// In both directories (compiler support version wins, forwards)
module stdint {
header "stdint.h"
}
}

View File

@ -0,0 +1 @@
// Testing hack: does not define bool/true/false.

View File

@ -0,0 +1 @@
typedef int my_awesome_nonstandard_integer_type;

View File

@ -0,0 +1,3 @@
typedef struct { int id; } FILE;
int fprintf(FILE*restrict, const char* restrict format, ...);

View File

@ -1,22 +1,6 @@
// RUN: rm -rf %t
// RUN: %clang -fsyntax-only -fmodules -fmodule-cache-path %t -D__need_wint_t %s -Xclang -verify
@import _Builtin_stdlib.float_constants;
float getFltMax() { return FLT_MAX; }
@import _Builtin_stdlib.limits;
char getCharMax() { return CHAR_MAX; }
// MS limits.h provides size_t.
// XFAIL: win32
size_t size; // expected-error{{unknown type name 'size_t'}}
@import _Builtin_stdlib.stdint;
intmax_t value;
#ifdef __SSE__
@import _Builtin_intrinsics.intel.sse;
#endif

29
clang/test/Modules/cstd.m Normal file
View File

@ -0,0 +1,29 @@
// RUN: rm -rf %t
// RUN: %clang -fsyntax-only -isysroot %S/Inputs/System -fmodules -fmodule-cache-path %t -D__need_wint_t %s -Xclang -verify
// Supplied by compiler, but referenced from the "/usr/include" module map.
@import cstd.float_constants;
float getFltMax() { return FLT_MAX; }
// Supplied by the "/usr/include" module map.
@import cstd.stdio;
void test_fprintf(FILE *file) {
fprintf(file, "Hello, modules\n");
}
// Supplied by compiler, which forwards to the the "/usr/include" version.
@import cstd.stdint;
my_awesome_nonstandard_integer_type value;
// Supplied by the compiler; that version wins.
@import cstd.stdbool;
#ifndef bool
# error "bool was not defined!"
#endif