Skip to content

Commit c3efd52

Browse files
committed
[clang][modules] Disallow importing private framework in the implementation
Whenever we are compiling implementation of a framework (with the `-fmodule-name=FW` option), we never translate `#import <FW/Header.h>` to an import, regardless of whether "Header.h" belongs to "FW" or "FW_Private". For the same reasons, we also disallow `@import FW`. However, we still allow `@import FW_Private`. This patch disallows that a well, to be consistent with the rest of the rules. Reviewed By: benlangmuir Differential Revision: https://reviews.llvm.org/D142167
1 parent 743fbcb commit c3efd52

File tree

5 files changed

+42
-28
lines changed

5 files changed

+42
-28
lines changed

clang/include/clang/Basic/Module.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,9 @@ class alignas(8) Module {
469469
bool isUnimportable(const LangOptions &LangOpts, const TargetInfo &Target,
470470
Requirement &Req, Module *&ShadowingModule) const;
471471

472+
/// Determine whether this module can be built in this compilation.
473+
bool isForBuilding(const LangOptions &LangOpts) const;
474+
472475
/// Determine whether this module is available for use within the
473476
/// current translation unit.
474477
bool isAvailable() const { return IsAvailable; }

clang/lib/Basic/Module.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,26 @@ bool Module::isUnimportable(const LangOptions &LangOpts,
148148
llvm_unreachable("could not find a reason why module is unimportable");
149149
}
150150

151+
// The -fmodule-name option tells the compiler to textually include headers in
152+
// the specified module, meaning Clang won't build the specified module. This
153+
// is useful in a number of situations, for instance, when building a library
154+
// that vends a module map, one might want to avoid hitting intermediate build
155+
// products containing the module map or avoid finding the system installed
156+
// modulemap for that library.
157+
bool Module::isForBuilding(const LangOptions &LangOpts) const {
158+
StringRef TopLevelName = getTopLevelModuleName();
159+
StringRef CurrentModule = LangOpts.CurrentModule;
160+
161+
// When building framework Foo, we want to make sure that Foo *and*
162+
// Foo_Private are textually included and no modules are built for both.
163+
if (getTopLevelModule()->IsFramework &&
164+
CurrentModule == LangOpts.ModuleName &&
165+
!CurrentModule.endswith("_Private") && TopLevelName.endswith("_Private"))
166+
TopLevelName = TopLevelName.drop_back(8);
167+
168+
return TopLevelName == CurrentModule;
169+
}
170+
151171
bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
152172
Requirement &Req,
153173
UnresolvedHeaderDirective &MissingHeader,

clang/lib/Lex/PPDirectives.cpp

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -109,25 +109,6 @@ enum PPElifDiag {
109109
PED_Elifndef
110110
};
111111

112-
// The -fmodule-name option tells the compiler to textually include headers in
113-
// the specified module, meaning clang won't build the specified module. This is
114-
// useful in a number of situations, for instance, when building a library that
115-
// vends a module map, one might want to avoid hitting intermediate build
116-
// products containimg the module map or avoid finding the system installed
117-
// modulemap for that library.
118-
static bool isForModuleBuilding(Module *M, StringRef CurrentModule,
119-
StringRef ModuleName) {
120-
StringRef TopLevelName = M->getTopLevelModuleName();
121-
122-
// When building framework Foo, we wanna make sure that Foo *and* Foo_Private
123-
// are textually included and no modules are built for both.
124-
if (M->getTopLevelModule()->IsFramework && CurrentModule == ModuleName &&
125-
!CurrentModule.endswith("_Private") && TopLevelName.endswith("_Private"))
126-
TopLevelName = TopLevelName.drop_back(8);
127-
128-
return TopLevelName == CurrentModule;
129-
}
130-
131112
static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) {
132113
const LangOptions &Lang = PP.getLangOpts();
133114
if (isReservedInAllContexts(II->isReserved(Lang))) {
@@ -2219,14 +2200,13 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
22192200
alreadyIncluded(*File))
22202201
Action = IncludeLimitReached;
22212202

2222-
bool MaybeTranslateInclude = Action == Enter && File && SuggestedModule &&
2223-
!isForModuleBuilding(SuggestedModule.getModule(),
2224-
getLangOpts().CurrentModule,
2225-
getLangOpts().ModuleName);
2226-
22272203
// FIXME: We do not have a good way to disambiguate C++ clang modules from
22282204
// C++ standard modules (other than use/non-use of Header Units).
22292205
Module *SM = SuggestedModule.getModule();
2206+
2207+
bool MaybeTranslateInclude =
2208+
Action == Enter && File && SM && !SM->isForBuilding(getLangOpts());
2209+
22302210
// Maybe a usable Header Unit
22312211
bool UsableHeaderUnit = false;
22322212
if (getLangOpts().CPlusPlusModules && SM && SM->isHeaderUnit()) {
@@ -2556,9 +2536,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
25562536
// that behaves the same as the header would behave in a compilation using
25572537
// that PCH, which means we should enter the submodule. We need to teach
25582538
// the AST serialization layer to deal with the resulting AST.
2559-
if (getLangOpts().CompilingPCH &&
2560-
isForModuleBuilding(SM, getLangOpts().CurrentModule,
2561-
getLangOpts().ModuleName))
2539+
if (getLangOpts().CompilingPCH && SM->isForBuilding(getLangOpts()))
25622540
return {ImportAction::None};
25632541

25642542
assert(!CurLexerSubmodule && "should not have marked this as a module yet");

clang/lib/Sema/SemaModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
541541
// of the same top-level module. Until we do, make it an error rather than
542542
// silently ignoring the import.
543543
// FIXME: Should we warn on a redundant import of the current module?
544-
if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule &&
544+
if (Mod->isForBuilding(getLangOpts()) &&
545545
(getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) {
546546
Diag(ImportLoc, getLangOpts().isCompilingModule()
547547
? diag::err_module_self_import
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
4+
//--- frameworks/FW.framework/Modules/module.modulemap
5+
framework module FW {}
6+
//--- frameworks/FW.framework/Modules/module.private.modulemap
7+
framework module FW_Private {}
8+
9+
//--- tu.m
10+
@import FW_Private; // expected-error{{@import of module 'FW_Private' in implementation of 'FW'; use #import}}
11+
12+
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fimplicit-module-maps \
13+
// RUN: -fmodule-name=FW -F %t/frameworks %t/tu.m -verify

0 commit comments

Comments
 (0)