jansvoboda11 created this revision.
jansvoboda11 added reviewers: Bigcheese, dexonsmith, rsmith.
jansvoboda11 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

When using explicit Clang modules, some declarations might unexpectedly become 
invisible.

This was noticed in the following scenario:

- module named `Interface` contains an ObjC interface declaration of the same 
name, and its PCM is passed to Clang via the `-fmodule-file=<path>` argument,
- another module referring to `Interface` within an attribute (`objc_bridge`) 
is passed to Clang (also via the `-fmodule-file=<path>` argument),
- the Clang invocation then can't find the `Interface` interface declaration.

This seems to be caused by the mechanism that loads PCM files passed via 
`-fmodule-file=<path>` which creates an `IdentifierInfo` for the module name. 
I'm not sure why exactly that trips up name resolution, but using `StringRef` 
for the module name resolves the error. Creating an `IdentifierInfo` with some 
prefix (e.g. `CI.getPreprocessor().getIdentifierInfo("LoadModuleCacheKey_" + 
ModuleName)`) also resolves the issue.

Note that the `-fmodule-file=<name>=<path>` form of the argument doesn't suffer 
from this issue, since it doesn't create `IdentifierInfo` for the module name.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D111543

Files:
  clang/include/clang/Lex/ModuleMap.h
  clang/lib/Frontend/CompilerInstance.cpp
  clang/test/Modules/Inputs/interface-visibility-2/Interface.h
  clang/test/Modules/Inputs/interface-visibility-2/InterfaceBridge.h
  clang/test/Modules/Inputs/interface-visibility-2/module.modulemap
  clang/test/Modules/interface-visibility-2.m

Index: clang/test/Modules/interface-visibility-2.m
===================================================================
--- /dev/null
+++ clang/test/Modules/interface-visibility-2.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/interface-visibility-2/module.modulemap -o %t/InterfaceBridge.pcm
+
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-name=Interface \
+// RUN:   %S/Inputs/interface-visibility-2/module.modulemap -o %t/Interface.pcm
+
+// Check that the `-fmodule-file=<name>=<path>` form succeeds:
+// RUN: %clang_cc1 -fmodules -fsyntax-only %s -I %S/Inputs/Interface-visibility-2 \
+// RUN:   -fmodule-file=InterfaceBridge=%t/InterfaceBridge.pcm -fmodule-file=Interface=%t/Interface.pcm \
+// RUN:   -fmodule-map-file=%S/Inputs/interface-visibility-2/module.modulemap -verify
+
+// Check that the `-fmodule-file=<path>` form succeeds:
+// RUN: %clang_cc1 -fmodules -fsyntax-only %s -I %S/Inputs/Interface-visibility-2 \
+// RUN:   -fmodule-file=%t/InterfaceBridge.pcm -fmodule-file=%t/Interface.pcm \
+// RUN:   -fmodule-map-file=%S/Inputs/interface-visibility-2/module.modulemap -verify
+
+#import "InterfaceBridge.h"
+#import "Interface.h"
+
+@interface Interface (User)
+@end
+
+// expected-no-diagnostics
Index: clang/test/Modules/Inputs/interface-visibility-2/module.modulemap
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/interface-visibility-2/module.modulemap
@@ -0,0 +1,7 @@
+module InterfaceBridge {
+  header "InterfaceBridge.h"
+}
+
+module Interface {
+  header "Interface.h"
+}
Index: clang/test/Modules/Inputs/interface-visibility-2/InterfaceBridge.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/interface-visibility-2/InterfaceBridge.h
@@ -0,0 +1 @@
+typedef struct __attribute__((objc_bridge(Interface))) Foo *Bar;
Index: clang/test/Modules/Inputs/interface-visibility-2/Interface.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/interface-visibility-2/Interface.h
@@ -0,0 +1,2 @@
+@interface Interface
+@end
Index: clang/lib/Frontend/CompilerInstance.cpp
===================================================================
--- clang/lib/Frontend/CompilerInstance.cpp
+++ clang/lib/Frontend/CompilerInstance.cpp
@@ -1617,28 +1617,27 @@
   // the files we were handed.
   struct ReadModuleNames : ASTReaderListener {
     CompilerInstance &CI;
-    llvm::SmallVector<IdentifierInfo*, 8> LoadedModules;
+    llvm::SmallVector<StringRef, 8> 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.cacheModuleLoad(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
@@ -1924,7 +1923,7 @@
   // If we don't already have information on this module, load the module now.
   Module *Module = nullptr;
   ModuleMap &MM = getPreprocessor().getHeaderSearchInfo().getModuleMap();
-  if (auto MaybeModule = MM.getCachedModuleLoad(*Path[0].first)) {
+  if (auto MaybeModule = MM.getCachedModuleLoad(ModuleName)) {
     // Use the cached result, which may be nullptr.
     Module = *MaybeModule;
   } else if (ModuleName == getLangOpts().CurrentModule) {
@@ -1940,7 +1939,7 @@
     //  DisableGeneratingGlobalModuleIndex = true;
     //  return ModuleLoadResult();
     //}
-    MM.cacheModuleLoad(*Path[0].first, Module);
+    MM.cacheModuleLoad(ModuleName, Module);
   } else {
     ModuleLoadResult Result = findOrCompileModuleAndReadAST(
         ModuleName, ImportLoc, ModuleNameLoc, IsInclusionDirective);
@@ -1949,7 +1948,7 @@
     if (!Result)
       DisableGeneratingGlobalModuleIndex = true;
     Module = Result;
-    MM.cacheModuleLoad(*Path[0].first, Module);
+    MM.cacheModuleLoad(ModuleName, Module);
   }
 
   // If we never found the module, fail.  Otherwise, verify the module and link
Index: clang/include/clang/Lex/ModuleMap.h
===================================================================
--- clang/include/clang/Lex/ModuleMap.h
+++ clang/include/clang/Lex/ModuleMap.h
@@ -101,9 +101,9 @@
   /// The top-level modules that are known.
   llvm::StringMap<Module *> Modules;
 
-  /// Module loading cache that includes submodules, indexed by IdentifierInfo.
+  /// Module loading cache that includes submodules, indexed by module names.
   /// nullptr is stored for modules that are known to fail to load.
-  llvm::DenseMap<const IdentifierInfo *, Module *> CachedModuleLoads;
+  llvm::StringMap<Module *> CachedModuleLoads;
 
   /// Shadow modules created while building this module map.
   llvm::SmallVector<Module*, 2> ShadowModules;
@@ -703,13 +703,13 @@
   }
 
   /// Cache a module load.  M might be nullptr.
-  void cacheModuleLoad(const IdentifierInfo &II, Module *M) {
-    CachedModuleLoads[&II] = M;
+  void cacheModuleLoad(StringRef ModuleName, Module *M) {
+    CachedModuleLoads[ModuleName] = M;
   }
 
   /// Return a cached module load.
-  llvm::Optional<Module *> getCachedModuleLoad(const IdentifierInfo &II) {
-    auto I = CachedModuleLoads.find(&II);
+  llvm::Optional<Module *> getCachedModuleLoad(StringRef ModuleName) {
+    auto I = CachedModuleLoads.find(ModuleName);
     if (I == CachedModuleLoads.end())
       return None;
     return I->second;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to