Skip to content

Commit 0874112

Browse files
committed
[clang][modules] Fix local submodule visibility of macros from transitive import (llvm#122955)
When we mark a module visible, we normally mark all of its non-explicit submodules and other exports as visible. However, when we first enter a submodule we should not make them visible to the submodule itself until they are actually imported. Marking exports visible before import would cause bizarre behaviour with local submodule visibility, because it happened before we discovered the submodule's transitive imports and could fail to make them visible in the parent module depending on whether the submodules involved were explicitly defined (module X) or implicitly defined from an umbrella (module *). rdar://136524433 (cherry picked from commit 4bb04d4)
1 parent fddf0af commit 0874112

File tree

6 files changed

+85
-16
lines changed

6 files changed

+85
-16
lines changed

clang/include/clang/Basic/Module.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -907,10 +907,11 @@ class VisibleModuleSet {
907907
StringRef Message)>;
908908

909909
/// Make a specific module visible.
910-
void setVisible(Module *M, SourceLocation Loc,
911-
VisibleCallback Vis = [](Module *) {},
912-
ConflictCallback Cb = [](ArrayRef<Module *>, Module *,
913-
StringRef) {});
910+
void setVisible(
911+
Module *M, SourceLocation Loc, bool IncludeExports = true,
912+
VisibleCallback Vis = [](Module *) {},
913+
ConflictCallback Cb = [](ArrayRef<Module *>, Module *, StringRef) {});
914+
914915
private:
915916
/// Import locations for each visible module. Indexed by the module's
916917
/// VisibilityID.

clang/include/clang/Lex/Preprocessor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1766,7 +1766,8 @@ class Preprocessor {
17661766
bool LexAfterModuleImport(Token &Result);
17671767
void CollectPpImportSuffix(SmallVectorImpl<Token> &Toks);
17681768

1769-
void makeModuleVisible(Module *M, SourceLocation Loc);
1769+
void makeModuleVisible(Module *M, SourceLocation Loc,
1770+
bool IncludeExports = true);
17701771

17711772
SourceLocation getModuleImportLoc(Module *M) const {
17721773
return CurSubmoduleState->VisibleModules.getImportLoc(M);

clang/lib/Basic/Module.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,8 @@ LLVM_DUMP_METHOD void Module::dump() const {
678678
}
679679

680680
void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc,
681-
VisibleCallback Vis, ConflictCallback Cb) {
681+
bool IncludeExports, VisibleCallback Vis,
682+
ConflictCallback Cb) {
682683
// We can't import a global module fragment so the location can be invalid.
683684
assert((M->isGlobalModule() || Loc.isValid()) &&
684685
"setVisible expects a valid import location");
@@ -704,12 +705,14 @@ void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc,
704705
Vis(V.M);
705706

706707
// Make any exported modules visible.
707-
SmallVector<Module *, 16> Exports;
708-
V.M->getExportedModules(Exports);
709-
for (Module *E : Exports) {
710-
// Don't import non-importable modules.
711-
if (!E->isUnimportable())
712-
VisitModule({E, &V});
708+
if (IncludeExports) {
709+
SmallVector<Module *, 16> Exports;
710+
V.M->getExportedModules(Exports);
711+
for (Module *E : Exports) {
712+
// Don't import non-importable modules.
713+
if (!E->isUnimportable())
714+
VisitModule({E, &V});
715+
}
713716
}
714717

715718
for (auto &C : V.M->Conflicts) {

clang/lib/Lex/PPLexerChange.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -759,9 +759,10 @@ void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc,
759759
// Switch to this submodule as the current submodule.
760760
CurSubmoduleState = &State;
761761

762-
// This module is visible to itself.
762+
// This module is visible to itself, but exports should not be made visible
763+
// until they are imported.
763764
if (FirstTime)
764-
makeModuleVisible(M, ImportLoc);
765+
makeModuleVisible(M, ImportLoc, /*IncludeExports=*/false);
765766
}
766767

767768
bool Preprocessor::needModuleMacros() const {

clang/lib/Lex/Preprocessor.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,9 +1336,10 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
13361336
return true;
13371337
}
13381338

1339-
void Preprocessor::makeModuleVisible(Module *M, SourceLocation Loc) {
1339+
void Preprocessor::makeModuleVisible(Module *M, SourceLocation Loc,
1340+
bool IncludeExports) {
13401341
CurSubmoduleState->VisibleModules.setVisible(
1341-
M, Loc, [](Module *) {},
1342+
M, Loc, IncludeExports, [](Module *) {},
13421343
[&](ArrayRef<Module *> Path, Module *Conflict, StringRef Message) {
13431344
// FIXME: Include the path in the diagnostic.
13441345
// FIXME: Include the import location for the conflicting module.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Checks that macros from transitive imports work with local submodule
2+
// visibility. In the below test, previously a() and d() failed because
3+
// OTHER_MACRO1 and OTHER_MACRO3 were not visible at the use site.
4+
5+
// RUN: rm -rf %t
6+
// RUN: split-file %s %t
7+
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \
8+
// RUN: -fmodules-local-submodule-visibility -I%t %t/tu.c -verify
9+
10+
//--- Other1.h
11+
#define OTHER_MACRO1(...)
12+
13+
//--- Other2.h
14+
#define OTHER_MACRO2(...)
15+
16+
//--- Other3.h
17+
#define OTHER_MACRO3(...)
18+
19+
//--- module.modulemap
20+
module Other {
21+
module O1 { header "Other1.h" }
22+
module O2 { header "Other2.h" }
23+
module O3 { header "Other3.h" }
24+
}
25+
26+
//--- Top/A.h
27+
#include "Other1.h"
28+
#define MACRO_A OTHER_MACRO1(x, y)
29+
30+
//--- Top/B.h
31+
#include "Other2.h"
32+
#define MACRO_B OTHER_MACRO2(x, y)
33+
34+
//--- Top/C.h
35+
#include "D.h"
36+
37+
//--- Top/D.h
38+
#include "Other3.h"
39+
#define MACRO_D OTHER_MACRO3(x, y)
40+
41+
//--- Top/Top.h
42+
#include "A.h"
43+
#include "B.h"
44+
#include "C.h"
45+
46+
void a() MACRO_A;
47+
void b() MACRO_B;
48+
void d() MACRO_D;
49+
50+
//--- Top/module.modulemap
51+
module Top {
52+
umbrella header "Top.h"
53+
module A { header "A.h" export * }
54+
module D { header "D.h" export * }
55+
module * { export * }
56+
export *
57+
export Other.O3
58+
}
59+
60+
//--- tu.c
61+
#include "Top/Top.h"
62+
// expected-no-diagnostics

0 commit comments

Comments
 (0)