diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticFrontendKinds.td | 2 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticLexKinds.td | 2 | ||||
-rw-r--r-- | clang/include/clang/Basic/Module.h | 17 | ||||
-rw-r--r-- | clang/include/clang/Lex/ModuleMap.h | 4 | ||||
-rw-r--r-- | clang/lib/Basic/Module.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInstance.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Frontend/FrontendActions.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Lex/HeaderSearch.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Lex/ModuleMap.cpp | 55 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/submodules/module.map | 5 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/unnecessary-module-map-parsing/module.map | 2 | ||||
-rw-r--r-- | clang/test/Modules/submodules.cpp | 5 | ||||
-rw-r--r-- | clang/test/Modules/unnecessary-module-map-parsing.c | 2 |
13 files changed, 86 insertions, 49 deletions
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 65a11cbc665..b0b140d6192 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -140,6 +140,8 @@ def warn_missing_submodule : Warning<"missing submodule '%0'">, InGroup<IncompleteUmbrella>; def err_module_unavailable : Error< "module '%0' %select{is incompatible with|requires}1 feature '%2'">; +def err_module_header_missing : Error< + "%select{|umbrella }0header '%1' not found">; def warn_module_config_macro_undef : Warning< "%select{definition|#undef}0 of configuration macro '%1' has no effect on " "the import of '%2'; pass '%select{-D%1=...|-U%1}0' on the command line " diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index e9de4db0368..e59ded86e79 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -551,8 +551,6 @@ def err_mmap_expected_mmap_file : Error<"expected a module map file name">; def err_mmap_module_redefinition : Error< "redefinition of module '%0'">; def note_mmap_prev_definition : Note<"previously defined here">; -def err_mmap_header_not_found : Error< - "%select{|umbrella }0header '%1' not found">; def err_mmap_umbrella_dir_not_found : Error< "umbrella directory '%0' not found">; def err_mmap_umbrella_clash : Error< diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h index e8d774e1eb5..a760ae3ce69 100644 --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -88,7 +88,19 @@ public: SmallVector<const FileEntry *, 2> ExcludedHeaders; /// \brief The headers that are private to this module. - llvm::SmallVector<const FileEntry *, 2> PrivateHeaders; + SmallVector<const FileEntry *, 2> PrivateHeaders; + + /// \brief Information about a header directive as found in the module map + /// file. + struct HeaderDirective { + SourceLocation FileNameLoc; + std::string FileName; + bool IsUmbrella; + }; + + /// \brief Headers that are mentioned in the module map file but could not be + /// found on the file system. + SmallVector<HeaderDirective, 1> MissingHeaders; /// \brief An individual requirement: a feature name and a flag indicating /// the required state of that feature. @@ -276,7 +288,8 @@ public: /// this module. bool isAvailable(const LangOptions &LangOpts, const TargetInfo &Target, - Requirement &Req) const; + Requirement &Req, + HeaderDirective &MissingHeader) const; /// \brief Determine whether this module is a submodule. bool isSubModule() const { return Parent != 0; } diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 483ae3d592a..5339ec13b29 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -38,7 +38,7 @@ class ModuleMapParser; class ModuleMap { SourceManager &SourceMgr; - IntrusiveRefCntPtr<DiagnosticsEngine> Diags; + DiagnosticsEngine &Diags; const LangOptions &LangOpts; const TargetInfo *Target; HeaderSearch &HeaderInfo; @@ -188,7 +188,7 @@ public: /// \param LangOpts Language options for this translation unit. /// /// \param Target The target for this translation unit. - ModuleMap(SourceManager &SourceMgr, DiagnosticConsumer &DC, + ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags, const LangOptions &LangOpts, const TargetInfo *Target, HeaderSearch &HeaderInfo); diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index d08cef1a156..c6a1d602a94 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -69,11 +69,15 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts, bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target, - Requirement &Req) const { + Requirement &Req, HeaderDirective &MissingHeader) const { if (IsAvailable) return true; for (const Module *Current = this; Current; Current = Current->Parent) { + if (!Current->MissingHeaders.empty()) { + MissingHeader = Current->MissingHeaders.front(); + return false; + } for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) { if (hasFeature(Current->Requirements[I].first, LangOpts, Target) != Current->Requirements[I].second) { diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index eccb94cc4a4..48ba0056071 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1360,11 +1360,19 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // Check whether this module is available. clang::Module::Requirement Requirement; - if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement)) { - getDiagnostics().Report(ImportLoc, diag::err_module_unavailable) - << Module->getFullModuleName() - << Requirement.second << Requirement.first - << SourceRange(Path.front().second, Path.back().second); + clang::Module::HeaderDirective MissingHeader; + if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement, + MissingHeader)) { + if (MissingHeader.FileNameLoc.isValid()) { + getDiagnostics().Report(MissingHeader.FileNameLoc, + diag::err_module_header_missing) + << MissingHeader.IsUmbrella << MissingHeader.FileName; + } else { + getDiagnostics().Report(ImportLoc, diag::err_module_unavailable) + << Module->getFullModuleName() + << Requirement.second << Requirement.first + << SourceRange(Path.front().second, Path.back().second); + } LastModuleImportLoc = ImportLoc; LastModuleImportResult = ModuleLoadResult(); return ModuleLoadResult(); diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index b5f15830024..e0c68c84a3e 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -247,10 +247,17 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, // Check whether we can build this module at all. clang::Module::Requirement Requirement; - if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement)) { - CI.getDiagnostics().Report(diag::err_module_unavailable) - << Module->getFullModuleName() - << Requirement.second << Requirement.first; + clang::Module::HeaderDirective MissingHeader; + if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement, + MissingHeader)) { + if (MissingHeader.FileNameLoc.isValid()) { + CI.getDiagnostics().Report(diag::err_module_header_missing) + << MissingHeader.IsUmbrella << MissingHeader.FileName; + } else { + CI.getDiagnostics().Report(diag::err_module_unavailable) + << Module->getFullModuleName() + << Requirement.second << Requirement.first; + } return false; } diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 5770aaadf40..254c0293df9 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -48,7 +48,7 @@ HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts, const LangOptions &LangOpts, const TargetInfo *Target) : HSOpts(HSOpts), FileMgr(SourceMgr.getFileManager()), FrameworkMap(64), - ModMap(SourceMgr, *Diags.getClient(), LangOpts, Target, *this) + ModMap(SourceMgr, Diags, LangOpts, Target, *this) { AngledDirIdx = 0; SystemDirIdx = 0; diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 8a1fcaa69e7..b9a47031289 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -59,7 +59,7 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod, Module *Context = lookupModuleUnqualified(Id[0].first, Mod); if (!Context) { if (Complain) - Diags->Report(Id[0].second, diag::err_mmap_missing_module_unqualified) + Diags.Report(Id[0].second, diag::err_mmap_missing_module_unqualified) << Id[0].first << Mod->getFullModuleName(); return 0; @@ -70,7 +70,7 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod, Module *Sub = lookupModuleQualified(Id[I].first, Context); if (!Sub) { if (Complain) - Diags->Report(Id[I].second, diag::err_mmap_missing_module_qualified) + Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified) << Id[I].first << Context->getFullModuleName() << SourceRange(Id[0].second, Id[I-1].second); @@ -83,19 +83,12 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod, return Context; } -ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticConsumer &DC, +ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags, const LangOptions &LangOpts, const TargetInfo *Target, HeaderSearch &HeaderInfo) - : SourceMgr(SourceMgr), LangOpts(LangOpts), Target(Target), + : SourceMgr(SourceMgr), Diags(Diags), LangOpts(LangOpts), Target(Target), HeaderInfo(HeaderInfo), BuiltinIncludeDir(0), CompilingModule(0), - SourceModule(0) { - IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs); - Diags = IntrusiveRefCntPtr<DiagnosticsEngine>( - new DiagnosticsEngine(DiagIDs, new DiagnosticOptions)); - Diags->setClient(new ForwardingDiagnosticConsumer(DC), - /*ShouldOwnClient=*/true); - Diags->setSourceManager(&SourceMgr); -} + SourceModule(0) {} ModuleMap::~ModuleMap() { for (llvm::StringMap<Module *>::iterator I = Modules.begin(), @@ -1480,12 +1473,13 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, HadError = true; return; } - std::string FileName = Tok.getString(); - SourceLocation FileNameLoc = consumeToken(); + Module::HeaderDirective Header; + Header.FileName = Tok.getString(); + Header.FileNameLoc = consumeToken(); // Check whether we already have an umbrella. if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) { - Diags.Report(FileNameLoc, diag::err_mmap_umbrella_clash) + Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash) << ActiveModule->getFullModuleName(); HadError = true; return; @@ -1495,12 +1489,12 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, const FileEntry *File = 0; const FileEntry *BuiltinFile = 0; SmallString<128> PathName; - if (llvm::sys::path::is_absolute(FileName)) { - PathName = FileName; + if (llvm::sys::path::is_absolute(Header.FileName)) { + PathName = Header.FileName; File = SourceMgr.getFileManager().getFile(PathName); } else if (const DirectoryEntry *Dir = getOverriddenHeaderSearchDir()) { PathName = Dir->getName(); - llvm::sys::path::append(PathName, FileName); + llvm::sys::path::append(PathName, Header.FileName); File = SourceMgr.getFileManager().getFile(PathName); } else { // Search for the header file within the search directory. @@ -1511,18 +1505,18 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, appendSubframeworkPaths(ActiveModule, PathName); // Check whether this file is in the public headers. - llvm::sys::path::append(PathName, "Headers", FileName); + llvm::sys::path::append(PathName, "Headers", Header.FileName); File = SourceMgr.getFileManager().getFile(PathName); if (!File) { // Check whether this file is in the private headers. PathName.resize(PathLength); - llvm::sys::path::append(PathName, "PrivateHeaders", FileName); + llvm::sys::path::append(PathName, "PrivateHeaders", Header.FileName); File = SourceMgr.getFileManager().getFile(PathName); } } else { // Lookup for normal headers. - llvm::sys::path::append(PathName, FileName); + llvm::sys::path::append(PathName, Header.FileName); File = SourceMgr.getFileManager().getFile(PathName); // If this is a system module with a top-level header, this header @@ -1530,9 +1524,9 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, // supplied by Clang. Find that builtin header. if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword && BuiltinIncludeDir && BuiltinIncludeDir != Directory && - isBuiltinHeader(FileName)) { + isBuiltinHeader(Header.FileName)) { SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName()); - llvm::sys::path::append(BuiltinPathName, FileName); + llvm::sys::path::append(BuiltinPathName, Header.FileName); BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName); // If Clang supplies this header but the underlying system does not, @@ -1577,10 +1571,13 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, } } else if (LeadingToken != MMToken::ExcludeKeyword) { // Ignore excluded header files. They're optional anyway. - - Diags.Report(FileNameLoc, diag::err_mmap_header_not_found) - << (LeadingToken == MMToken::UmbrellaKeyword) << FileName; - HadError = true; + + // If we find a module that has a missing header, we mark this module as + // unavailable and store the header directive for displaying diagnostics. + // Other submodules in the same module can still be used. + Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword; + ActiveModule->IsAvailable = false; + ActiveModule->MissingHeaders.push_back(Header); } } @@ -2119,11 +2116,9 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) { // Parse this module map file. Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts); - Diags->getClient()->BeginSourceFile(MMapLangOpts); - ModuleMapParser Parser(L, SourceMgr, Target, *Diags, *this, File->getDir(), + ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File->getDir(), BuiltinIncludeDir, IsSystem); bool Result = Parser.parseModuleMapFile(); - Diags->getClient()->EndSourceFile(); ParsedModuleMap[File] = Result; return Result; } diff --git a/clang/test/Modules/Inputs/submodules/module.map b/clang/test/Modules/Inputs/submodules/module.map index c91e94f47d2..15931031abb 100644 --- a/clang/test/Modules/Inputs/submodules/module.map +++ b/clang/test/Modules/Inputs/submodules/module.map @@ -10,3 +10,8 @@ module import_self { module c { header "import-self-c.h" } module d { header "import-self-d.h" } } + +module missing_headers { + module missing { header "missing.h" } + module not_missing { header "not_missing.h" } +} diff --git a/clang/test/Modules/Inputs/unnecessary-module-map-parsing/module.map b/clang/test/Modules/Inputs/unnecessary-module-map-parsing/module.map index 2d2104177ff..6d4ceeeb0cc 100644 --- a/clang/test/Modules/Inputs/unnecessary-module-map-parsing/module.map +++ b/clang/test/Modules/Inputs/unnecessary-module-map-parsing/module.map @@ -1,3 +1,3 @@ module a { - header "unknown.h" + eader "unknown.h" } diff --git a/clang/test/Modules/submodules.cpp b/clang/test/Modules/submodules.cpp index 9c62389eadc..12bf87f6307 100644 --- a/clang/test/Modules/submodules.cpp +++ b/clang/test/Modules/submodules.cpp @@ -34,3 +34,8 @@ extern MyTypeC import_self_test_c; // FIXME: This should be valid; import_self.b re-exports import_self.d. extern MyTypeD import_self_test_d; // expected-error {{must be imported from module 'import_self.d'}} // expected-note@import-self-d.h:1 {{here}} + +// expected-error@Inputs/submodules/module.map:15{{header 'missing.h' not found}} +@import missing_headers.missing; +@import missing_headers.not_missing; +void f() { NotMissingFunction(); }; diff --git a/clang/test/Modules/unnecessary-module-map-parsing.c b/clang/test/Modules/unnecessary-module-map-parsing.c index 16f7086a6d7..4c83448179e 100644 --- a/clang/test/Modules/unnecessary-module-map-parsing.c +++ b/clang/test/Modules/unnecessary-module-map-parsing.c @@ -3,6 +3,6 @@ // RUN: not %clang_cc1 -fmodules -I %S/Inputs/unnecessary-module-map-parsing -fsyntax-only %s 2>&1 | FileCheck %s // RUN: %clang_cc1 -I %S/Inputs/unnecessary-module-map-parsing -fsyntax-only %s -// CHECK: error: header 'unknown.h' not found +// CHECK: error: expected umbrella, header, submodule, or module export #include "a1.h" |