From: Douglas Gregor Date: Tue, 6 Dec 2011 17:16:41 +0000 (+0000) Subject: Implement modules support for subframeworks (aka embedded X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d620a84a01cc232a9449dbcc2c40bd43ca314fc9;p=clang Implement modules support for subframeworks (aka embedded frameworks). A submodule can now be labeled as a "framework", and header search will look into the appropriate Headers/PrivateHeaders subdirectories for named headers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145941 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 286a7ef40e..e0bf38c102 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -395,8 +395,6 @@ def err_mmap_header_not_found : Error< "%select{|umbrella }0header '%1' not found">; def err_mmap_umbrella_header_conflict : Error< "module '%0' already has an umbrella header ('%1')">; -def err_mmap_umbrella_header_submodule : Error< - "submodule '%0' can not have an umbrella header">; def err_mmap_umbrella_clash : Error< "umbrella header for module '%0' already covers this directory">; def err_mmap_export_module_id : Error< diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 198544dd51..5f3379bf96 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -251,6 +251,8 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, Result->InferSubmodules = true; Result->InferExportWildcard = true; + // FIXME: Look for subframeworks. + Modules[ModuleName] = Result; return Result; } @@ -559,19 +561,21 @@ void ModuleMapParser::parseModuleDecl() { assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) || Tok.is(MMToken::FrameworkKeyword)); - // Parse 'framework' or 'explicit' keyword, if present. - bool Framework = false; + // Parse 'explicit' or 'framework' keyword, if present. bool Explicit = false; + bool Framework = false; - if (Tok.is(MMToken::FrameworkKeyword)) { - consumeToken(); - Framework = true; - } // Parse 'explicit' keyword, if present. - else if (Tok.is(MMToken::ExplicitKeyword)) { + if (Tok.is(MMToken::ExplicitKeyword)) { consumeToken(); Explicit = true; } + + // Parse 'framework' keyword, if present. + if (Tok.is(MMToken::FrameworkKeyword)) { + consumeToken(); + Framework = true; + } // Parse 'module' keyword. if (!Tok.is(MMToken::ModuleKeyword)) { @@ -640,6 +644,7 @@ void ModuleMapParser::parseModuleDecl() { break; case MMToken::ExplicitKeyword: + case MMToken::FrameworkKeyword: case MMToken::ModuleKeyword: parseModuleDecl(); break; @@ -674,7 +679,27 @@ void ModuleMapParser::parseModuleDecl() { // We're done parsing this module. Pop back to our parent scope. ActiveModule = ActiveModule->Parent; } - + +/// \brief Append to \p Paths the set of paths needed to get to the +/// subframework in which the given module lives. +void appendSubframeworkPaths(Module *Mod, llvm::SmallVectorImpl &Path) { + // Collect the framework names from the given module to the top-level module. + llvm::SmallVector Paths; + for (; Mod; Mod = Mod->Parent) { + if (Mod->IsFramework) + Paths.push_back(Mod->Name); + } + + if (Paths.empty()) + return; + + // Add Frameworks/Name.framework for each subframework. + for (unsigned I = Paths.size() - 1; I != 0; --I) { + llvm::sys::path::append(Path, "Frameworks"); + llvm::sys::path::append(Path, Paths[I-1] + ".framework"); + } +} + /// \brief Parse an umbrella header declaration. /// /// umbrella-declaration: @@ -702,14 +727,6 @@ void ModuleMapParser::parseUmbrellaDecl() { return; } - // Only top-level modules can have umbrella headers. - if (ActiveModule->Parent) { - Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_header_submodule) - << ActiveModule->getFullModuleName(); - HadError = true; - return; - } - // Look for this file. llvm::SmallString<128> PathName; const FileEntry *File = 0; @@ -721,7 +738,10 @@ void ModuleMapParser::parseUmbrellaDecl() { // Search for the header file within the search directory. PathName += Directory->getName(); unsigned PathLength = PathName.size(); + if (ActiveModule->isPartOfFramework()) { + appendSubframeworkPaths(ActiveModule, PathName); + // Check whether this file is in the public headers. llvm::sys::path::append(PathName, "Headers"); llvm::sys::path::append(PathName, FileName); @@ -734,8 +754,6 @@ void ModuleMapParser::parseUmbrellaDecl() { llvm::sys::path::append(PathName, FileName); File = SourceMgr.getFileManager().getFile(PathName); } - - // FIXME: Deal with subframeworks. } else { // Lookup for normal headers. llvm::sys::path::append(PathName, FileName); @@ -797,8 +815,10 @@ void ModuleMapParser::parseHeaderDecl() { // FIXME: Change this search to also look for private headers! PathName += Directory->getName(); - if (ActiveModule->isPartOfFramework()) + if (ActiveModule->isPartOfFramework()) { + appendSubframeworkPaths(ActiveModule, PathName); llvm::sys::path::append(PathName, "Headers"); + } } llvm::sys::path::append(PathName, FileName); diff --git a/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h new file mode 100644 index 0000000000..69f9e8e4d0 --- /dev/null +++ b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h @@ -0,0 +1 @@ +double *sub_framework_other; diff --git a/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h new file mode 100644 index 0000000000..e6e835ecc4 --- /dev/null +++ b/test/Modules/Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h @@ -0,0 +1,2 @@ +#include "SubFramework/Other.h" +float *sub_framework; diff --git a/test/Modules/Inputs/DependsOnModule.framework/module.map b/test/Modules/Inputs/DependsOnModule.framework/module.map index d4c2a67061..d771275285 100644 --- a/test/Modules/Inputs/DependsOnModule.framework/module.map +++ b/test/Modules/Inputs/DependsOnModule.framework/module.map @@ -4,4 +4,7 @@ framework module DependsOnModule { module * { export * } + explicit framework module SubFramework { + umbrella "SubFramework.h" + } } diff --git a/test/Modules/subframeworks.m b/test/Modules/subframeworks.m new file mode 100644 index 0000000000..44b6746a4a --- /dev/null +++ b/test/Modules/subframeworks.m @@ -0,0 +1,16 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify + +__import_module__ DependsOnModule; + +void testSubFramework() { + float *sf1 = sub_framework; // expected-error{{use of undeclared identifier 'sub_framework'}} +} + +__import_module__ DependsOnModule.SubFramework; + +void testSubFrameworkAgain() { + float *sf2 = sub_framework; + double *sfo1 = sub_framework_other; +} +