diff options
-rw-r--r-- | include/clang/Basic/DiagnosticLexKinds.td | 11 | ||||
-rw-r--r-- | include/clang/Lex/ModuleMap.h | 6 | ||||
-rw-r--r-- | include/clang/Serialization/ASTBitCodes.h | 16 | ||||
-rw-r--r-- | lib/Frontend/FrontendActions.cpp | 23 | ||||
-rw-r--r-- | lib/Lex/ModuleMap.cpp | 83 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 24 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 16 | ||||
-rw-r--r-- | test/Modules/Inputs/normal-module-map/module.map | 5 | ||||
-rw-r--r-- | test/Modules/Inputs/normal-module-map/nested_umbrella/a.h | 2 | ||||
-rw-r--r-- | test/Modules/Inputs/normal-module-map/nested_umbrella/b.h | 2 | ||||
-rw-r--r-- | test/Modules/normal-module-map.cpp | 18 |
11 files changed, 179 insertions, 27 deletions
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 2cf115d728..cbaa407d3f 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -382,8 +382,9 @@ def err_mmap_expected_lbrace : Error<"expected '{' to start module '%0'">; def err_mmap_expected_rbrace : Error<"expected '}'">; def note_mmap_lbrace_match : Note<"to match this '{'">; def err_mmap_expected_member : Error< - "expected umbrella header, header, submodule, or module export">; + "expected umbrella, header, submodule, or module export">; def err_mmap_expected_header : Error<"expected a header name after '%0'">; +def err_mmap_expected_dir : Error<"expected a directory name after '%0'">; def err_mmap_module_redefinition : Error< "redefinition of module '%0'">; def note_mmap_prev_definition : Note<"previously defined here">; @@ -391,10 +392,10 @@ def err_mmap_header_conflict : Error< "header '%0' is already part of module '%1'">; 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_dir_not_found : Error< + "umbrella directory '%0' not found">; def err_mmap_umbrella_clash : Error< - "umbrella header for module '%0' already covers this directory">; + "umbrella for module '%0' already covers this directory">; def err_mmap_export_module_id : Error< "expected an exported module name or '*'">; def err_mmap_missing_module_unqualified : Error< @@ -404,7 +405,7 @@ def err_mmap_missing_module_qualified : Error< def err_mmap_top_level_inferred_submodule : Error< "only submodules may be inferred with wildcard syntax">; def err_mmap_inferred_no_umbrella : Error< - "inferred submodules require a module with an umbrella header">; + "inferred submodules require a module with an umbrella">; def err_mmap_inferred_redef : Error< "redefinition of inferred submodule">; def err_mmap_expected_lbrace_wildcard : Error< diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h index 262e50db23..2d95255290 100644 --- a/include/clang/Lex/ModuleMap.h +++ b/include/clang/Lex/ModuleMap.h @@ -181,7 +181,11 @@ public: /// \brief Sets the umbrella header of the given module to the given /// header. void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader); - + + /// \brief Sets the umbrella directory of the given module to the given + /// directory. + void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir); + /// \brief Adds this header to the given module. void addHeader(Module *Mod, const FileEntry *Header); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 17c9992a6c..41ef74ee0a 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -507,22 +507,24 @@ namespace clang { /// \brief Record types used within a submodule description block. enum SubmoduleRecordTypes { + /// \brief Metadata for submodules as a whole. + SUBMODULE_METADATA = 0, /// \brief Defines the major attributes of a submodule, including its /// name and parent. - SUBMODULE_DEFINITION = 0, + SUBMODULE_DEFINITION = 1, /// \brief Specifies the umbrella header used to create this module, /// if any. - SUBMODULE_UMBRELLA = 1, + SUBMODULE_UMBRELLA_HEADER = 2, /// \brief Specifies a header that falls into this (sub)module. - SUBMODULE_HEADER = 2, - /// \brief Metadata for submodules as a whole. - SUBMODULE_METADATA = 3, + SUBMODULE_HEADER = 3, + /// \brief Specifies an umbrella directory. + SUBMODULE_UMBRELLA_DIR = 4, /// \brief Specifies the submodules that are imported by this /// submodule. - SUBMODULE_IMPORTS = 4, + SUBMODULE_IMPORTS = 5, /// \brief Specifies the submodules that are re-exported from this /// submodule. - SUBMODULE_EXPORTS = 5 + SUBMODULE_EXPORTS = 6 }; /// \defgroup ASTAST AST file AST constants diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 190cdba582..5dabe81996 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -21,6 +21,7 @@ #include "clang/Frontend/Utils.h" #include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" @@ -155,6 +156,28 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts, Includes += UmbrellaHeader->getName(); Includes += "\"\n"; } + } else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) { + // Add all of the headers we find in this subdirectory (FIXME: recursively!). + llvm::error_code EC; + llvm::SmallString<128> DirNative; + llvm::sys::path::native(UmbrellaDir->getName(), DirNative); + for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + // Check whether this entry has an extension typically associated with + // headers. + if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path())) + .Cases(".h", ".H", ".hh", ".hpp", true) + .Default(false)) + continue; + + // Include this header umbrella header for submodules. + if (LangOpts.ObjC1) + Includes += "#import \""; + else + Includes += "#include \""; + Includes += Dir->path(); + Includes += "\"\n"; + } } // Recurse into submodules. diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index e4c9d77ad6..c9efbf0b53 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -346,6 +346,11 @@ void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){ UmbrellaDirs[UmbrellaDir] = Mod; } +void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) { + Mod->Umbrella = UmbrellaDir; + UmbrellaDirs[UmbrellaDir] = Mod; +} + void ModuleMap::addHeader(Module *Mod, const FileEntry *Header) { Mod->Headers.push_back(Header); Headers[Header] = Mod; @@ -494,6 +499,7 @@ namespace clang { bool parseModuleId(ModuleId &Id); void parseModuleDecl(); void parseHeaderDecl(SourceLocation UmbrellaLoc); + void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); void parseExportDecl(); void parseInferredSubmoduleDecl(bool Explicit); @@ -796,9 +802,14 @@ void ModuleMapParser::parseModuleDecl() { parseExportDecl(); break; - case MMToken::UmbrellaKeyword: - parseHeaderDecl(consumeToken()); + case MMToken::UmbrellaKeyword: { + SourceLocation UmbrellaLoc = consumeToken(); + if (Tok.is(MMToken::HeaderKeyword)) + parseHeaderDecl(UmbrellaLoc); + else + parseUmbrellaDirDecl(UmbrellaLoc); break; + } case MMToken::HeaderKeyword: parseHeaderDecl(SourceLocation()); @@ -863,11 +874,10 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) { std::string FileName = Tok.getString(); SourceLocation FileNameLoc = consumeToken(); - // Check whether we already have an umbrella header. - if (Umbrella && ActiveModule->getUmbrellaHeader()) { - Diags.Report(FileNameLoc, diag::err_mmap_umbrella_header_conflict) - << ActiveModule->getFullModuleName() - << ActiveModule->getUmbrellaHeader()->getName(); + // Check whether we already have an umbrella. + if (Umbrella && ActiveModule->Umbrella) { + Diags.Report(FileNameLoc, diag::err_mmap_umbrella_clash) + << ActiveModule->getFullModuleName(); HadError = true; return; } @@ -935,9 +945,62 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) { } } else { Diags.Report(FileNameLoc, diag::err_mmap_header_not_found) - << false << FileName; + << Umbrella << FileName; + HadError = true; + } +} + +/// \brief Parse an umbrella directory declaration. +/// +/// umbrella-dir-declaration: +/// umbrella string-literal +void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) { + // Parse the directory name. + if (!Tok.is(MMToken::StringLiteral)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) + << "umbrella"; + HadError = true; + return; + } + + std::string DirName = Tok.getString(); + SourceLocation DirNameLoc = consumeToken(); + + // Check whether we already have an umbrella. + if (ActiveModule->Umbrella) { + Diags.Report(DirNameLoc, diag::err_mmap_umbrella_clash) + << ActiveModule->getFullModuleName(); + HadError = true; + return; + } + + // Look for this file. + const DirectoryEntry *Dir = 0; + if (llvm::sys::path::is_absolute(DirName)) + Dir = SourceMgr.getFileManager().getDirectory(DirName); + else { + llvm::SmallString<128> PathName; + PathName = Directory->getName(); + llvm::sys::path::append(PathName, DirName); + Dir = SourceMgr.getFileManager().getDirectory(PathName); + } + + if (!Dir) { + Diags.Report(DirNameLoc, diag::err_mmap_umbrella_dir_not_found) + << DirName; HadError = true; + return; } + + if (Module *OwningModule = Map.UmbrellaDirs[Dir]) { + Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash) + << OwningModule->getFullModuleName(); + HadError = true; + return; + } + + // Record this umbrella directory. + Map.setUmbrellaDir(ActiveModule, Dir); } /// \brief Parse a module export declaration. @@ -998,8 +1061,8 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) { Failed = true; } - // Inferred modules must have umbrella headers. - if (!Failed && !ActiveModule->getUmbrellaHeader()) { + // Inferred modules must have umbrella directories. + if (!Failed && !ActiveModule->getUmbrellaDir()) { Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella); Failed = true; } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 21be3aa50c..236c2bd1f5 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -3088,7 +3088,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { break; } - case SUBMODULE_UMBRELLA: { + case SUBMODULE_UMBRELLA_HEADER: { if (First) { Error("missing submodule metadata record at beginning of block"); return Failure; @@ -3129,6 +3129,28 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { break; } + case SUBMODULE_UMBRELLA_DIR: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return Failure; + } + + if (!CurrentModule) + break; + + StringRef DirName(BlobStart, BlobLen); + if (const DirectoryEntry *Umbrella + = PP.getFileManager().getDirectory(DirName)) { + if (!CurrentModule->getUmbrellaDir()) + ModMap.setUmbrellaDir(CurrentModule, Umbrella); + else if (CurrentModule->getUmbrellaDir() != Umbrella) { + Error("mismatched umbrella directories in submodule"); + return Failure; + } + } + break; + } + case SUBMODULE_METADATA: { if (!First) { Error("submodule metadata record not at beginning of block"); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 1bd9050fe0..83ad885969 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1900,7 +1900,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev); Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA)); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_HEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned UmbrellaAbbrev = Stream.EmitAbbrev(Abbrev); @@ -1908,7 +1908,12 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev); - + + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev); + // Write the submodule metadata block. RecordData Record; Record.push_back(getNumberOfModules(WritingModule)); @@ -1943,9 +1948,14 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { // Emit the umbrella header, if there is one. if (const FileEntry *UmbrellaHeader = Mod->getUmbrellaHeader()) { Record.clear(); - Record.push_back(SUBMODULE_UMBRELLA); + Record.push_back(SUBMODULE_UMBRELLA_HEADER); Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record, UmbrellaHeader->getName()); + } else if (const DirectoryEntry *UmbrellaDir = Mod->getUmbrellaDir()) { + Record.clear(); + Record.push_back(SUBMODULE_UMBRELLA_DIR); + Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record, + UmbrellaDir->getName()); } // Emit the headers. diff --git a/test/Modules/Inputs/normal-module-map/module.map b/test/Modules/Inputs/normal-module-map/module.map index 91e4bf7178..e17f44a8f4 100644 --- a/test/Modules/Inputs/normal-module-map/module.map +++ b/test/Modules/Inputs/normal-module-map/module.map @@ -6,3 +6,8 @@ module libA { module libB { header "b1.h" } + +module nested_umbrella { + umbrella "nested_umbrella" + module * { } +} diff --git a/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h b/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h new file mode 100644 index 0000000000..ab180fe073 --- /dev/null +++ b/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h @@ -0,0 +1,2 @@ +int nested_umbrella_a; + diff --git a/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h b/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h new file mode 100644 index 0000000000..a903f5d8ab --- /dev/null +++ b/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h @@ -0,0 +1,2 @@ +int nested_umbrella_b; + diff --git a/test/Modules/normal-module-map.cpp b/test/Modules/normal-module-map.cpp index 19294950d4..5a7d549053 100644 --- a/test/Modules/normal-module-map.cpp +++ b/test/Modules/normal-module-map.cpp @@ -1,3 +1,5 @@ +// Note: inside the module. expected-note{{ 'nested_umbrella_a' declared here}} + // RUN: rm -rf %t // RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/normal-module-map %s -verify #include "Umbrella/umbrella_sub.h" @@ -15,3 +17,19 @@ __import_module__ Umbrella2; int test() { return a1 + b1 + nested2; } + +__import_module__ nested_umbrella.a; + +int testNestedUmbrellaA() { + return nested_umbrella_a; +} + +int testNestedUmbrellaBFail() { + return nested_umbrella_b; // expected-error{{use of undeclared identifier 'nested_umbrella_b'; did you mean 'nested_umbrella_a'?}} +} + +__import_module__ nested_umbrella.b; + +int testNestedUmbrellaB() { + return nested_umbrella_b; +} |