diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h index ae79650d1fd0b7744ef8cf00aa383ecb6a50d904..70770d17e9ffa4abb0fc048315afc1dbe15b38cc 100644 --- a/include/clang/Lex/ModuleLoader.h +++ b/include/clang/Lex/ModuleLoader.h @@ -31,13 +31,22 @@ typedef ArrayRef<std::pair<IdentifierInfo *, SourceLocation> > ModuleIdPath; /// \brief Describes the result of attempting to load a module. class ModuleLoadResult { - llvm::PointerIntPair<Module *, 1, bool> Storage; - public: - ModuleLoadResult() : Storage() { } + enum LoadResultKind { + // We either succeeded or failed to load the named module. + Normal, + // The module exists, but does not actually contain the named submodule. + // This should only happen if the named submodule was inferred from an + // umbrella directory, but not actually part of the umbrella header. + MissingExpected, + // The module exists but cannot be imported due to a configuration mismatch. + ConfigMismatch + }; + llvm::PointerIntPair<Module *, 2, LoadResultKind> Storage; - ModuleLoadResult(Module *module, bool missingExpected) - : Storage(module, missingExpected) { } + ModuleLoadResult() : Storage() { } + ModuleLoadResult(Module *M) : Storage(M, Normal) {} + ModuleLoadResult(LoadResultKind Kind) : Storage(nullptr, Kind) {} operator Module *() const { return Storage.getPointer(); } @@ -45,7 +54,11 @@ public: /// actually a submodule that we expected to see (based on implying the /// submodule from header structure), but didn't materialize in the actual /// module. - bool isMissingExpected() const { return Storage.getInt(); } + bool isMissingExpected() const { return Storage.getInt() == MissingExpected; } + + /// \brief Determines whether the module failed to load due to a configuration + /// mismatch with an explicitly-named .pcm file from the command line. + bool isConfigMismatch() const { return Storage.getInt() == ConfigMismatch; } }; /// \brief Abstract interface for a module loader. diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index d314f6d18a6198529b160979137d53db9511a836..991e9ef990a0bce6a4206587382929cec0a13d6c 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -1393,8 +1393,21 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { if (Module *M = CI.getPreprocessor() .getHeaderSearchInfo() .getModuleMap() - .findModule(II->getName())) + .findModule(II->getName())) { M->HasIncompatibleModuleFile = true; + + // Mark module as available if the only reason it was unavailable + // was missing headers. + SmallVector<Module *, 2> Stack; + Stack.push_back(M); + while (!Stack.empty()) { + Module *Current = Stack.pop_back_val(); + if (Current->IsMissingRequirement) continue; + Current->IsAvailable = true; + Stack.insert(Stack.end(), + Current->submodule_begin(), Current->submodule_end()); + } + } } LoadedModules.clear(); } @@ -1498,7 +1511,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, if (Module && Module->HasIncompatibleModuleFile) { // We tried and failed to load a module file for this module. Fall // back to textual inclusion for its headers. - return ModuleLoadResult(nullptr, /*missingExpected*/true); + return ModuleLoadResult::ConfigMismatch; } getDiagnostics().Report(ModuleNameLoc, diag::err_module_build_disabled) @@ -1705,7 +1718,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, << Module->getFullModuleName() << SourceRange(Path.front().second, Path.back().second); - return ModuleLoadResult(nullptr, true); + return ModuleLoadResult::MissingExpected; } // Check whether this module is available. @@ -1739,7 +1752,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, } LastModuleImportLoc = ImportLoc; - LastModuleImportResult = ModuleLoadResult(Module, false); + LastModuleImportResult = ModuleLoadResult(Module); return LastModuleImportResult; } diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 7fc008274bdb4f2ba671be6015e81e90bdcb93ec..85504de3d15d864eefe996f922f19ded13ef2741 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -1866,10 +1866,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // unavailable, diagnose the situation and bail out. // FIXME: Remove this; loadModule does the same check (but produces // slightly worse diagnostics). - if (!SuggestedModule.getModule()->isAvailable() && - !SuggestedModule.getModule() - ->getTopLevelModule() - ->HasIncompatibleModuleFile) { + if (!SuggestedModule.getModule()->isAvailable()) { Module::Requirement Requirement; Module::UnresolvedHeaderDirective MissingHeader; Module *M = SuggestedModule.getModule(); @@ -1918,9 +1915,12 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, else if (Imported.isMissingExpected()) { // We failed to find a submodule that we assumed would exist (because it // was in the directory of an umbrella header, for instance), but no - // actual module exists for it (because the umbrella header is + // actual module containing it exists (because the umbrella header is // incomplete). Treat this as a textual inclusion. SuggestedModule = ModuleMap::KnownHeader(); + } else if (Imported.isConfigMismatch()) { + // On a configuration mismatch, enter the header textually. We still know + // that it's part of the corresponding module. } else { // We hit an error processing the import. Bail out. if (hadModuleLoaderFatalFailure()) { diff --git a/test/Modules/config-mismatch.cpp b/test/Modules/config-mismatch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..548e78452df3bc00b8a46bd8edee40708cddb67b --- /dev/null +++ b/test/Modules/config-mismatch.cpp @@ -0,0 +1,10 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: echo 'module M { header "foo.h" header "bar.h" }' > %t/map +// RUN: echo 'template<typename T> void f(T t) { int n; t.f(n); }' > %t/foo.h +// RUN: touch %t/bar.h +// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -x c++ %t/map -emit-module -fmodule-name=M -o %t/pcm +// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fmodule-map-file=%t/map -fmodule-file=%t/pcm -I%t %s -fsyntax-only -fexceptions -Wno-module-file-config-mismatch +// RUN: rm %t/bar.h +// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fmodule-map-file=%t/map -fmodule-file=%t/pcm -I%t %s -fsyntax-only -fexceptions -Wno-module-file-config-mismatch +#include "foo.h"