diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -786,10 +786,11 @@ /// ModuleMap. First attempt to load it from the given path on disk. If that /// fails, defer to compileModuleAndReadAST, which will first build and then /// load it. - ModuleLoadResult findOrCompileModuleAndReadAST(StringRef ModuleName, - SourceLocation ImportLoc, - SourceLocation ModuleNameLoc, - bool IsInclusionDirective); + ModuleLoadResult + findOrCompileModuleAndReadAST(StringRef ModuleName, SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective); // Get the submodule corresponding to the module path. Module *getSubmoduleCorrespondingToPath( diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1772,9 +1772,24 @@ return MS_ModuleNotFound; } +static ModuleLoadResult handleMissingSubmodule(DiagnosticsEngine &Diags, + Module *SubM, + SourceLocation ImportLoc, + ModuleIdPath Path) { + // We have an umbrella header or directory that doesn't actually include all + // the headers within the directory it covers. Complain about this missing + // submodule and recover by forgetting that we ever saw this submodule. + Diags.Report(ImportLoc, diag::warn_missing_submodule) + << SubM->getFullModuleName() + << SourceRange(Path.front().second, Path.back().second); + + return ModuleLoadResult::MissingExpected; +} + ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( StringRef ModuleName, SourceLocation ImportLoc, - SourceLocation ModuleNameLoc, bool IsInclusionDirective) { + SourceLocation ModuleNameLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, bool IsInclusionDirective) { // Search for a module with the given name. HeaderSearch &HS = PP->getHeaderSearchInfo(); Module *M = @@ -1797,6 +1812,16 @@ return ModuleLoadResult::ConfigMismatch; } + bool MapPrivateSubModToTopLevel = false; + // FIXME: Should we detect this at module load time? It seems fairly + // expensive (and rare). + Module *SubM = getSubmoduleCorrespondingToPath( + MapPrivateSubModToTopLevel, M, ImportLoc, Path, Visibility, + IsInclusionDirective); + + if (SubM != M && !SubM->IsFromModuleFile && !MapPrivateSubModToTopLevel) + return handleMissingSubmodule(getDiagnostics(), SubM, ImportLoc, Path); + getDiagnostics().Report(ModuleNameLoc, diag::err_module_build_disabled) << ModuleName; return nullptr; @@ -2061,8 +2086,9 @@ //} MM.cacheModuleLoad(*Path[0].first, Module); } else { - ModuleLoadResult Result = findOrCompileModuleAndReadAST( - ModuleName, ImportLoc, ModuleNameLoc, IsInclusionDirective); + ModuleLoadResult Result = + findOrCompileModuleAndReadAST(ModuleName, ImportLoc, ModuleNameLoc, + Path, Visibility, IsInclusionDirective); if (!Result.isNormal()) return Result; if (!Result) @@ -2077,6 +2103,9 @@ return ModuleLoadResult(); bool MapPrivateSubModToTopLevel = false; + class Module *TopLevelModule = Module; + // FIXME: Should we detect this at module load time? It seems fairly + // expensive (and rare). Module = getSubmoduleCorrespondingToPath(MapPrivateSubModToTopLevel, Module, ImportLoc, Path, Visibility, IsInclusionDirective); @@ -2084,19 +2113,9 @@ // Make the named module visible, if it's not already part of the module // we are parsing. if (ModuleName != getLangOpts().CurrentModule) { - if (!Module->IsFromModuleFile && !MapPrivateSubModToTopLevel) { - // We have an umbrella header or directory that doesn't actually include - // all of the headers within the directory it covers. Complain about - // this missing submodule and recover by forgetting that we ever saw - // this submodule. - // FIXME: Should we detect this at module load time? It seems fairly - // expensive (and rare). - getDiagnostics().Report(ImportLoc, diag::warn_missing_submodule) - << Module->getFullModuleName() - << SourceRange(Path.front().second, Path.back().second); - - return ModuleLoadResult::MissingExpected; - } + if (Module != TopLevelModule && !Module->IsFromModuleFile && + !MapPrivateSubModToTopLevel) + return handleMissingSubmodule(getDiagnostics(), Module, ImportLoc, Path); // Check whether this module is available. if (Preprocessor::checkModuleIsAvailable(getLangOpts(), getTarget(), diff --git a/clang/test/Modules/missing-submodule.m b/clang/test/Modules/missing-submodule.m --- a/clang/test/Modules/missing-submodule.m +++ b/clang/test/Modules/missing-submodule.m @@ -1,5 +1,6 @@ // RUN: rm -rf %t // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -F %S/Inputs %s -verify +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fno-implicit-modules -F %S/Inputs %s -verify #include // expected-warning{{missing submodule 'Module.NotInModule'}} int getNotInModule() {