Index: include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- include/clang/Basic/DiagnosticCommonKinds.td +++ include/clang/Basic/DiagnosticCommonKinds.td @@ -84,6 +84,10 @@ def err_module_build_disabled: Error< "module '%0' is needed but has not been provided, and implicit use of module " "files is disabled">, DefaultFatal; +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 err_module_lock_failure : Error< "could not acquire lock file for module '%0'">, DefaultFatal; def err_module_lock_timeout : Error< Index: include/clang/Basic/DiagnosticFrontendKinds.td =================================================================== --- include/clang/Basic/DiagnosticFrontendKinds.td +++ include/clang/Basic/DiagnosticFrontendKinds.td @@ -173,10 +173,6 @@ "no submodule named %0 in module '%1'; did you mean '%2'?">; def warn_missing_submodule : Warning<"missing submodule '%0'">, InGroup; -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 err_module_cannot_create_includes : Error< "cannot create includes file for module %0: %1">; def warn_module_config_macro_undef : Warning< Index: include/clang/Basic/DiagnosticLexKinds.td =================================================================== --- include/clang/Basic/DiagnosticLexKinds.td +++ include/clang/Basic/DiagnosticLexKinds.td @@ -622,6 +622,8 @@ def warn_auto_module_import : Warning< "treating #%select{include|import|include_next|__include_macros}0 as an " "import of module '%1'">, InGroup, DefaultIgnore; +def note_implicit_top_level_module_import_here : Note< + "submodule of top-level module '%0' implicitly imported here">; def warn_uncovered_module_header : Warning< "umbrella header for module '%0' does not include header '%1'">, InGroup; Index: lib/Lex/ModuleMap.cpp =================================================================== --- lib/Lex/ModuleMap.cpp +++ lib/Lex/ModuleMap.cpp @@ -345,13 +345,9 @@ if (Known != Headers.end()) { ModuleMap::KnownHeader Result; // Iterate over all modules that 'File' is part of to find the best fit. - for (KnownHeader &H : Known->second) { - // Cannot use a module if it is unavailable. - if (!H.getModule()->isAvailable()) - continue; + for (KnownHeader &H : Known->second) if (!Result || isBetterKnownHeader(H, Result)) Result = H; - } return MakeResult(Result); } Index: lib/Lex/PPDirectives.cpp =================================================================== --- lib/Lex/PPDirectives.cpp +++ lib/Lex/PPDirectives.cpp @@ -1651,6 +1651,28 @@ } } + // If this include corresponds to a module but that module is + // unavailable, diagnose the situation and bail out. + if (SuggestedModule && !SuggestedModule.getModule()->isAvailable()) { + clang::Module::Requirement Requirement; + clang::Module::UnresolvedHeaderDirective MissingHeader; + Module *M = SuggestedModule.getModule(); + // Identify the cause. + (void)M->isAvailable(getLangOpts(), getTargetInfo(), Requirement, + MissingHeader); + if (MissingHeader.FileNameLoc.isValid()) { + Diag(MissingHeader.FileNameLoc, diag::err_module_header_missing) + << MissingHeader.IsUmbrella << MissingHeader.FileName; + Diag(FilenameTok.getLocation(), + diag::note_implicit_top_level_module_import_here) + << M->getTopLevelModuleName(); + } else { + Diag(MissingHeader.FileNameLoc, diag::err_module_unavailable) + << M->getFullModuleName() << Requirement.second << Requirement.first; + } + return; + } + // Should we enter the source file? Set to false if either the source file is // known to have no effect beyond its effect on module visibility -- that is, // if it's got an include guard that is already defined or is a modular header Index: test/Modules/Inputs/declare-use/module.map =================================================================== --- test/Modules/Inputs/declare-use/module.map +++ test/Modules/Inputs/declare-use/module.map @@ -20,14 +20,12 @@ module XE { header "e.h" - header "unavailable.h" use XA use XB } module XF { header "f.h" - header "unavailable.h" use XA use XB } Index: test/Modules/Inputs/macro-reexport/module.modulemap =================================================================== --- test/Modules/Inputs/macro-reexport/module.modulemap +++ test/Modules/Inputs/macro-reexport/module.modulemap @@ -19,5 +19,4 @@ } module f { module f1 { header "f1.h" export * } - module f2 { header "f2.h" export * } } Index: test/Modules/missing-header.cpp =================================================================== --- /dev/null +++ test/Modules/missing-header.cpp @@ -0,0 +1,13 @@ +// RUN: rm -rf %t +// RUN: not %clang_cc1 -x c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs/submodules %s 2>&1 | FileCheck %s + +// Even if the header we ask for is not missing, if the top-level module +// containing it has a missing header, then the whole top-level is +// unavailable and we issue an error. + +// CHECK: module.map:15:27: error: header 'missing.h' not found +// CHECK-DAG: missing-header.cpp:[[@LINE+1]]:10: note: submodule of top-level module 'missing_headers' implicitly imported here +#include "not_missing.h" + +// We should not attempt to build the module. +// CHECK-NOT: could not build module 'missing_headers'