Author: bruno
Date: Thu Dec 21 21:04:43 2017
New Revision: 321342

URL: http://llvm.org/viewvc/llvm-project?rev=321342&view=rev
Log:
[Modules] Map missing private submodules from Foo.Private to Foo_Private

In case `@import Foo.Private` fails because the submodule doesn't exist,
look for `Foo_Private` (if available) and build/load that module
instead. In that process emit a warning and tell the user about the
assumption.

The intention here is to assist all existing private modules owners
(in ObjC and Swift) to migrate to the new `Foo_Private` syntax.

rdar://problem/36023940

Added:
    cfe/trunk/test/Modules/implicit-map-dot-private.m
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
    cfe/trunk/lib/Frontend/CompilerInstance.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td?rev=321342&r1=321341&r2=321342&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Thu Dec 21 
21:04:43 2017
@@ -198,6 +198,11 @@ def err_missing_module : Error<
 def err_no_submodule : Error<"no submodule named %0 in module '%1'">;
 def err_no_submodule_suggest : Error<
   "no submodule named %0 in module '%1'; did you mean '%2'?">;
+def warn_no_priv_submodule_use_toplevel : Warning<
+  "no submodule named %0 in module '%1'; using top level '%2'">,
+  InGroup<PrivateModule>;
+def note_private_top_level_defined : Note<
+  "module defined here">;
 def warn_missing_submodule : Warning<"missing submodule '%0'">,
   InGroup<IncompleteUmbrella>;
 def note_module_import_here : Note<"module imported here">;

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=321342&r1=321341&r2=321342&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Thu Dec 21 21:04:43 2017
@@ -1854,6 +1854,7 @@ CompilerInstance::loadModule(SourceLocat
 
   // Verify that the rest of the module path actually corresponds to
   // a submodule.
+  bool MapPrivateSubModToTopLevel = false;
   if (!getLangOpts().ModulesTS && Path.size() > 1) {
     for (unsigned I = 1, N = Path.size(); I != N; ++I) {
       StringRef Name = Path[I].first->getName();
@@ -1892,7 +1893,40 @@ CompilerInstance::loadModule(SourceLocat
           Sub = Module->findSubmodule(Best[0]);
         }
       }
-      
+
+      // If the user is requesting Foo.Private and it doesn't exist, try to
+      // match Foo_Private and emit a warning asking for the user to write
+      // @import Foo_Private instead. FIXME: remove this when existing clients
+      // migrate off of Foo.Private syntax.
+      if (!Sub && PP->getLangOpts().ImplicitModules && Name == "Private" &&
+          Module == Module->getTopLevelModule()) {
+        SmallString<128> PrivateModule(Module->Name);
+        PrivateModule.append("_Private");
+
+        SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> PrivPath;
+        auto &II = PP->getIdentifierTable().get(
+            PrivateModule, PP->getIdentifierInfo(Module->Name)->getTokenID());
+        PrivPath.push_back(std::make_pair(&II, Path[0].second));
+
+        if (PP->getHeaderSearchInfo().lookupModule(PrivateModule))
+          Sub =
+              loadModule(ImportLoc, PrivPath, Visibility, 
IsInclusionDirective);
+        if (Sub) {
+          MapPrivateSubModToTopLevel = true;
+          if (!getDiagnostics().isIgnored(
+                  diag::warn_no_priv_submodule_use_toplevel, ImportLoc)) {
+            getDiagnostics().Report(Path[I].second,
+                                    diag::warn_no_priv_submodule_use_toplevel)
+                << Path[I].first << Module->getFullModuleName() << 
PrivateModule
+                << SourceRange(Path[0].second, Path[I].second)
+                << FixItHint::CreateReplacement(SourceRange(Path[0].second),
+                                                PrivateModule);
+            getDiagnostics().Report(Sub->DefinitionLoc,
+                                    diag::note_private_top_level_defined);
+          }
+        }
+      }
+
       if (!Sub) {
         // No submodule by this name. Complain, and don't look for further
         // submodules.
@@ -1909,7 +1943,7 @@ CompilerInstance::loadModule(SourceLocat
   // Make the named module visible, if it's not already part of the module
   // we are parsing.
   if (ModuleName != getLangOpts().CurrentModule) {
-    if (!Module->IsFromModuleFile) {
+    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

Added: cfe/trunk/test/Modules/implicit-map-dot-private.m
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/implicit-map-dot-private.m?rev=321342&view=auto
==============================================================================
--- cfe/trunk/test/Modules/implicit-map-dot-private.m (added)
+++ cfe/trunk/test/Modules/implicit-map-dot-private.m Thu Dec 21 21:04:43 2017
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -verify -fmodules -fimplicit-module-maps 
-fmodules-cache-path=%t -F %S/Inputs/implicit-private-canonical -emit-pch -o 
%t-A.pch %s -Wprivate-module
+
+#ifndef HEADER
+#define HEADER
+
+@import A.Private; // expected-warning {{no submodule named 'Private' in 
module 'A'; using top level 'A_Private'}}
+// 
expected-note@Inputs/implicit-private-canonical/A.framework/Modules/module.private.modulemap:1{{module
 defined here}}
+
+const int *y = &APRIVATE;
+
+#endif


_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to