Skip to content

Commit dba2b5c

Browse files
committed
[clang][modules] Skip submodule & framework re-definitions in module maps
Before D150478, there were situations when Clang avoided parsing a module map because it was likely to re-define an already defined module (either by a PCM or by previously-found module map). Since Clang no longer performs that check and does parse the extra module map (due to the FW/FW_Private issue described in D150478), this patch re-implements the same semantics by skipping the duplicate definition of the framework module while parsing the module map. Depends on D150478. Reviewed By: benlangmuir Differential Revision: https://reviews.llvm.org/D150479
1 parent be01456 commit dba2b5c

File tree

3 files changed

+62
-2
lines changed

3 files changed

+62
-2
lines changed

clang/lib/Lex/ModuleMap.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,20 +2016,37 @@ void ModuleMapParser::parseModuleDecl() {
20162016
Module *ShadowingModule = nullptr;
20172017
if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) {
20182018
// We might see a (re)definition of a module that we already have a
2019-
// definition for in three cases:
2019+
// definition for in four cases:
20202020
// - If we loaded one definition from an AST file and we've just found a
20212021
// corresponding definition in a module map file, or
20222022
bool LoadedFromASTFile = Existing->IsFromModuleFile;
20232023
// - If we previously inferred this module from different module map file.
20242024
bool Inferred = Existing->IsInferred;
2025+
// - If we're building a framework that vends a module map, we might've
2026+
// previously seen the one in intermediate products and now the system
2027+
// one.
2028+
// FIXME: If we're parsing module map file that looks like this:
2029+
// framework module FW { ... }
2030+
// module FW.Sub { ... }
2031+
// We can't check the framework qualifier, since it's not attached to
2032+
// the definition of Sub. Checking that qualifier on \c Existing is
2033+
// not correct either, since we might've previously seen:
2034+
// module FW { ... }
2035+
// module FW.Sub { ... }
2036+
// We should enforce consistency of redefinitions so that we can rely
2037+
// that \c Existing is part of a framework iff the redefinition of FW
2038+
// we have just skipped had it too. Once we do that, stop checking
2039+
// the local framework qualifier and only rely on \c Existing.
2040+
bool PartOfFramework = Framework || Existing->isPartOfFramework();
20252041
// - If we're building a (preprocessed) module and we've just loaded the
20262042
// module map file from which it was created.
20272043
bool ParsedAsMainInput =
20282044
Map.LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap &&
20292045
Map.LangOpts.CurrentModule == ModuleName &&
20302046
SourceMgr.getDecomposedLoc(ModuleNameLoc).first !=
20312047
SourceMgr.getDecomposedLoc(Existing->DefinitionLoc).first;
2032-
if (!ActiveModule && (LoadedFromASTFile || Inferred || ParsedAsMainInput)) {
2048+
if (LoadedFromASTFile || Inferred || PartOfFramework || ParsedAsMainInput) {
2049+
ActiveModule = PreviousActiveModule;
20332050
// Skip the module definition.
20342051
skipUntil(MMToken::RBrace);
20352052
if (Tok.is(MMToken::RBrace))
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
4+
//--- frameworks1/FW1.framework/Modules/module.modulemap
5+
framework module FW1 { header "FW1.h" }
6+
//--- frameworks1/FW1.framework/Headers/FW1.h
7+
#import <FW2/FW2.h>
8+
9+
//--- frameworks2/FW2.framework/Modules/module.modulemap
10+
framework module FW2 { header "FW2.h" }
11+
//--- frameworks2/FW2.framework/Modules/module.private.modulemap
12+
framework module FW2.Private { header "FW2_Private.h" }
13+
//--- frameworks2/FW2.framework/Headers/FW2.h
14+
//--- frameworks2/FW2.framework/PrivateHeaders/FW2_Private.h
15+
16+
//--- tu.c
17+
#import <FW1/FW1.h> // expected-remark{{importing module 'FW1'}} \
18+
// expected-remark{{importing module 'FW2'}}
19+
#import <FW2/FW2_Private.h> // expected-remark{{importing module 'FW2'}}
20+
21+
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fimplicit-module-maps \
22+
// RUN: -F %t/frameworks1 -F %t/frameworks2 -fsyntax-only %t/tu.c \
23+
// RUN: -fno-modules-check-relocated -Rmodule-import -verify

clang/test/Modules/shadow-framework.m

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
4+
// This test checks that redefinitions of frameworks are ignored.
5+
6+
//--- include/module.modulemap
7+
module first { header "first.h" }
8+
module FW {}
9+
//--- include/first.h
10+
11+
//--- frameworks/FW.framework/Modules/module.modulemap
12+
framework module FW { header "FW.h" }
13+
//--- frameworks/FW.framework/Headers/FW.h
14+
15+
//--- tu.c
16+
#import "first.h" // expected-remark {{importing module 'first'}}
17+
#import <FW/FW.h>
18+
19+
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fimplicit-module-maps \
20+
// RUN: -I %t/include -F %t/frameworks -fsyntax-only %t/tu.c -Rmodule-import -verify

0 commit comments

Comments
 (0)