From 22d97065d358d977eab163c6e07540072eea2642 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Wed, 2 May 2018 02:25:03 +0000 Subject: [PATCH] [Modules] Allow @import to reach submodules in private module maps A @import targeting a top level module from a private module map file (@import Foo_Private), would fail if there's any submodule declaration around (module Foo.SomeSub) in the same private module map. This happens because compileModuleImpl, when building Foo_Private, will start with the private module map and will not parse the public one, which leads to unsuccessful parsing of Foo.SomeSub, since top level Foo was never parsed. Declaring other submodules in the private module map is not common and should usually be avoided, but it shouldn't fail to build. Canonicalize compileModuleImpl to always look at the public module first, so that all necessary information is available when parsing the private one. rdar://problem/39822328 llvm-svn: 331322 --- clang/lib/Frontend/CompilerInstance.cpp | 20 +++++++++++++++++++ .../A.framework/Headers/A.h | 1 + .../A.framework/Headers/SomeSub.h | 0 .../A.framework/Modules/module.modulemap | 3 +++ .../Modules/module.private.modulemap | 7 +++++++ .../A.framework/PrivateHeaders/APrivate.h | 0 .../test/Modules/submodule-in-private-mmap.m | 7 +++++++ 7 files changed, 38 insertions(+) create mode 100644 clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Headers/A.h create mode 100644 clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Headers/SomeSub.h create mode 100644 clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Modules/module.modulemap create mode 100644 clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Modules/module.private.modulemap create mode 100644 clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/PrivateHeaders/APrivate.h create mode 100644 clang/test/Modules/submodule-in-private-mmap.m diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index f57246bec098..4199cbe0f667 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1188,6 +1188,19 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, return !Instance.getDiagnostics().hasErrorOccurred(); } +static const FileEntry *getPublicModuleMap(const FileEntry *File, + FileManager &FileMgr) { + StringRef Filename = llvm::sys::path::filename(File->getName()); + SmallString<128> PublicFilename(File->getDir()->getName()); + if (Filename == "module_private.map") + llvm::sys::path::append(PublicFilename, "module.map"); + else if (Filename == "module.private.modulemap") + llvm::sys::path::append(PublicFilename, "module.modulemap"); + else + return nullptr; + return FileMgr.getFile(PublicFilename); +} + /// \brief Compile a module file for the given module, using the options /// provided by the importing compiler instance. Returns true if the module /// was built without errors. @@ -1204,6 +1217,13 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, bool Result; if (const FileEntry *ModuleMapFile = ModMap.getContainingModuleMapFile(Module)) { + // Canonicalize compilation to start with the public module map. This is + // vital for submodules declarations in the private module maps to be + // correctly parsed when depending on a top level module in the public one. + if (const FileEntry *PublicMMFile = getPublicModuleMap( + ModuleMapFile, ImportingInstance.getFileManager())) + ModuleMapFile = PublicMMFile; + // Use the module map where this module resides. Result = compileModuleImpl( ImportingInstance, ImportLoc, Module->getTopLevelModuleName(), diff --git a/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Headers/A.h b/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Headers/A.h new file mode 100644 index 000000000000..975f1f0437bb --- /dev/null +++ b/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Headers/A.h @@ -0,0 +1 @@ +// A.h diff --git a/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Headers/SomeSub.h b/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Headers/SomeSub.h new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Modules/module.modulemap b/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Modules/module.modulemap new file mode 100644 index 000000000000..afa48392e94a --- /dev/null +++ b/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Modules/module.modulemap @@ -0,0 +1,3 @@ +framework module A { + header "A.h" +} diff --git a/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Modules/module.private.modulemap b/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Modules/module.private.modulemap new file mode 100644 index 000000000000..1dbd9fb8096b --- /dev/null +++ b/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/Modules/module.private.modulemap @@ -0,0 +1,7 @@ +framework module A_Private { + header "APrivate.h" +} + +module A.SomeSub { + header "SomeSub.h" +} diff --git a/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/PrivateHeaders/APrivate.h b/clang/test/Modules/Inputs/submodule-in-private-mmap/A.framework/PrivateHeaders/APrivate.h new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Modules/submodule-in-private-mmap.m b/clang/test/Modules/submodule-in-private-mmap.m new file mode 100644 index 000000000000..50e50108757f --- /dev/null +++ b/clang/test/Modules/submodule-in-private-mmap.m @@ -0,0 +1,7 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -F%S/Inputs/submodule-in-private-mmap -fsyntax-only %s -Wno-private-module -verify + +// expected-no-diagnostics + +@import A.Private; +@import A.SomeSub;