diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -101,6 +101,10 @@ /// The top-level modules that are known. llvm::StringMap Modules; + /// Top-module loading cache, indexed by module names. + /// nullptr is stored for modules that are known to fail to load. + llvm::StringMap CachedTopLevelModuleLoads; + /// Module loading cache that includes submodules, indexed by IdentifierInfo. /// nullptr is stored for modules that are known to fail to load. llvm::DenseMap CachedModuleLoads; @@ -707,12 +711,22 @@ CachedModuleLoads[&II] = M; } + /// Cache a top-level module load. M might be nullptr. + void cacheTopLevelModuleLoad(StringRef ModuleName, Module *M) { + CachedTopLevelModuleLoads[ModuleName] = M; + } + /// Return a cached module load. llvm::Optional getCachedModuleLoad(const IdentifierInfo &II) { - auto I = CachedModuleLoads.find(&II); - if (I == CachedModuleLoads.end()) - return None; - return I->second; + auto It1 = CachedModuleLoads.find(&II); + if (It1 != CachedModuleLoads.end()) + return It1->second; + + auto It2 = CachedTopLevelModuleLoads.find(II.getName()); + if (It2 != CachedTopLevelModuleLoads.end()) + return CachedModuleLoads[&II] = It2->second; + + return None; } }; 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 @@ -1639,28 +1639,27 @@ // the files we were handed. struct ReadModuleNames : ASTReaderListener { CompilerInstance &CI; - llvm::SmallVector LoadedModules; + llvm::SmallVector LoadedModules; ReadModuleNames(CompilerInstance &CI) : CI(CI) {} void ReadModuleName(StringRef ModuleName) override { - LoadedModules.push_back( - CI.getPreprocessor().getIdentifierInfo(ModuleName)); + LoadedModules.push_back(ModuleName); } void registerAll() { ModuleMap &MM = CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(); - for (auto *II : LoadedModules) - MM.cacheModuleLoad(*II, MM.findModule(II->getName())); + for (StringRef LoadedModule : LoadedModules) + MM.cacheTopLevelModuleLoad(LoadedModule, MM.findModule(LoadedModule)); LoadedModules.clear(); } void markAllUnavailable() { - for (auto *II : LoadedModules) { + for (StringRef LoadedModule : LoadedModules) { if (Module *M = CI.getPreprocessor() .getHeaderSearchInfo() .getModuleMap() - .findModule(II->getName())) { + .findModule(LoadedModule)) { M->HasIncompatibleModuleFile = true; // Mark module as available if the only reason it was unavailable diff --git a/clang/test/Modules/Inputs/module-name-used-by-objc-bridge/Interface.h b/clang/test/Modules/Inputs/module-name-used-by-objc-bridge/Interface.h new file mode 100644 --- /dev/null +++ b/clang/test/Modules/Inputs/module-name-used-by-objc-bridge/Interface.h @@ -0,0 +1,2 @@ +@interface Interface +@end diff --git a/clang/test/Modules/Inputs/module-name-used-by-objc-bridge/InterfaceBridge.h b/clang/test/Modules/Inputs/module-name-used-by-objc-bridge/InterfaceBridge.h new file mode 100644 --- /dev/null +++ b/clang/test/Modules/Inputs/module-name-used-by-objc-bridge/InterfaceBridge.h @@ -0,0 +1 @@ +typedef struct __attribute__((objc_bridge(Interface))) Foo *Bar; diff --git a/clang/test/Modules/Inputs/module-name-used-by-objc-bridge/module.modulemap b/clang/test/Modules/Inputs/module-name-used-by-objc-bridge/module.modulemap new file mode 100644 --- /dev/null +++ b/clang/test/Modules/Inputs/module-name-used-by-objc-bridge/module.modulemap @@ -0,0 +1,7 @@ +module InterfaceBridge { + header "InterfaceBridge.h" +} + +module Interface { + header "Interface.h" +} diff --git a/clang/test/Modules/module-name-used-by-objc-bridge.m b/clang/test/Modules/module-name-used-by-objc-bridge.m new file mode 100644 --- /dev/null +++ b/clang/test/Modules/module-name-used-by-objc-bridge.m @@ -0,0 +1,25 @@ +// RUN: rm -rf %t && mkdir %t + +// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-name=InterfaceBridge \ +// RUN: %S/Inputs/module-name-used-by-objc-bridge/module.modulemap -o %t/InterfaceBridge.pcm + +// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-name=Interface \ +// RUN: %S/Inputs/module-name-used-by-objc-bridge/module.modulemap -o %t/Interface.pcm + +// Check that the `-fmodule-file==` form succeeds: +// RUN: %clang_cc1 -fmodules -fsyntax-only %s -I %S/Inputs/module-name-used-by-objc-bridge \ +// RUN: -fmodule-file=InterfaceBridge=%t/InterfaceBridge.pcm -fmodule-file=Interface=%t/Interface.pcm \ +// RUN: -fmodule-map-file=%S/Inputs/module-name-used-by-objc-bridge/module.modulemap -verify + +// Check that the `-fmodule-file=` form succeeds: +// RUN: %clang_cc1 -fmodules -fsyntax-only %s -I %S/Inputs/module-name-used-by-objc-bridge \ +// RUN: -fmodule-file=%t/InterfaceBridge.pcm -fmodule-file=%t/Interface.pcm \ +// RUN: -fmodule-map-file=%S/Inputs/module-name-used-by-objc-bridge/module.modulemap -verify + +#import "InterfaceBridge.h" +#import "Interface.h" + +@interface Interface (User) +@end + +// expected-no-diagnostics