forked from OSchip/llvm-project
Implement support for wildcard exports in modules, allowing a module
to re-export anything that it imports. This opt-in feature makes a module behave more like a header, because it can be used to re-export the transitive closure of a (sub)module's dependencies. llvm-svn: 145811
This commit is contained in:
parent
13231037f0
commit
f5eedd05db
|
@ -128,6 +128,10 @@ public:
|
|||
/// \brief Determine whether this module is a submodule.
|
||||
bool isSubModule() const { return Parent != 0; }
|
||||
|
||||
/// \brief Determine whether this module is a submodule of the given other
|
||||
/// module.
|
||||
bool isSubModuleOf(Module *Other) const;
|
||||
|
||||
/// \brief Determine whether this module is a part of a framework,
|
||||
/// either because it is a framework module or because it is a submodule
|
||||
/// of a framework module.
|
||||
|
|
|
@ -25,6 +25,18 @@ Module::~Module() {
|
|||
|
||||
}
|
||||
|
||||
bool Module::isSubModuleOf(Module *Other) const {
|
||||
const Module *This = this;
|
||||
do {
|
||||
if (This == Other)
|
||||
return true;
|
||||
|
||||
This = This->Parent;
|
||||
} while (This);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Module::getFullModuleName() const {
|
||||
llvm::SmallVector<StringRef, 2> Names;
|
||||
|
||||
|
|
|
@ -31,6 +31,12 @@ Module::ExportDecl
|
|||
ModuleMap::resolveExport(Module *Mod,
|
||||
const Module::UnresolvedExportDecl &Unresolved,
|
||||
bool Complain) {
|
||||
// We may have just a wildcard.
|
||||
if (Unresolved.Id.empty()) {
|
||||
assert(Unresolved.Wildcard && "Invalid unresolved export");
|
||||
return Module::ExportDecl(0, true);
|
||||
}
|
||||
|
||||
// Find the starting module.
|
||||
Module *Context = lookupModuleUnqualified(Unresolved.Id[0].first, Mod);
|
||||
if (!Context) {
|
||||
|
@ -229,7 +235,7 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
|
|||
for (unsigned I = 0, N = Mod->UnresolvedExports.size(); I != N; ++I) {
|
||||
Module::ExportDecl Export = resolveExport(Mod, Mod->UnresolvedExports[I],
|
||||
Complain);
|
||||
if (Export.getPointer())
|
||||
if (Export.getPointer() || Export.getInt())
|
||||
Mod->Exports.push_back(Export);
|
||||
else
|
||||
HadError = true;
|
||||
|
@ -764,6 +770,7 @@ void ModuleMapParser::parseExportDecl() {
|
|||
|
||||
if(Tok.is(MMToken::Star)) {
|
||||
Wildcard = true;
|
||||
consumeToken();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -2520,15 +2520,60 @@ void ASTReader::makeModuleVisible(Module *Mod,
|
|||
}
|
||||
|
||||
// Push any exported modules onto the stack to be marked as visible.
|
||||
bool AnyWildcard = false;
|
||||
bool UnrestrictedWildcard = false;
|
||||
llvm::SmallVector<Module *, 4> WildcardRestrictions;
|
||||
for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) {
|
||||
Module *Exported = Mod->Exports[I].getPointer();
|
||||
if (Visited.insert(Exported)) {
|
||||
// FIXME: The intent of wildcards is to re-export any imported modules.
|
||||
// However, we don't yet have the module-dependency information to do
|
||||
// this, so we ignore wildcards for now.
|
||||
if (!Mod->Exports[I].getInt())
|
||||
if (!Mod->Exports[I].getInt()) {
|
||||
// Export a named module directly; no wildcards involved.
|
||||
if (Visited.insert(Exported))
|
||||
Stack.push_back(Exported);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wildcard export: export all of the imported modules that match
|
||||
// the given pattern.
|
||||
AnyWildcard = true;
|
||||
if (UnrestrictedWildcard)
|
||||
continue;
|
||||
|
||||
if (Module *Restriction = Mod->Exports[I].getPointer())
|
||||
WildcardRestrictions.push_back(Restriction);
|
||||
else {
|
||||
WildcardRestrictions.clear();
|
||||
UnrestrictedWildcard = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If there were any wildcards, push any imported modules that were
|
||||
// re-exported by the wildcard restriction.
|
||||
if (!AnyWildcard)
|
||||
continue;
|
||||
|
||||
for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
|
||||
Module *Imported = Mod->Imports[I];
|
||||
if (Visited.count(Imported))
|
||||
continue;
|
||||
|
||||
bool Acceptable = UnrestrictedWildcard;
|
||||
if (!Acceptable) {
|
||||
// Check whether this module meets one of the restrictions.
|
||||
for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) {
|
||||
Module *Restriction = WildcardRestrictions[R];
|
||||
if (Imported == Restriction || Imported->isSubModuleOf(Restriction)) {
|
||||
Acceptable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Acceptable)
|
||||
continue;
|
||||
|
||||
Visited.insert(Imported);
|
||||
Stack.push_back(Imported);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2563,13 +2608,17 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
|
|||
for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) {
|
||||
UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I];
|
||||
SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID);
|
||||
if (Module *ResolvedMod = getSubmodule(GlobalID)) {
|
||||
if (Unresolved.IsImport)
|
||||
Module *ResolvedMod = getSubmodule(GlobalID);
|
||||
|
||||
if (Unresolved.IsImport) {
|
||||
if (ResolvedMod)
|
||||
Unresolved.Mod->Imports.push_back(ResolvedMod);
|
||||
else
|
||||
Unresolved.Mod->Exports.push_back(
|
||||
Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ResolvedMod || Unresolved.IsWildcard)
|
||||
Unresolved.Mod->Exports.push_back(
|
||||
Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
|
||||
}
|
||||
UnresolvedModuleImportExports.clear();
|
||||
|
||||
|
|
|
@ -1957,7 +1957,8 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
|
|||
Record.clear();
|
||||
for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) {
|
||||
unsigned ExportedID = SubmoduleIDs[Mod->Exports[I].getPointer()];
|
||||
assert(ExportedID && "Unknown submodule!");
|
||||
assert((ExportedID || !Mod->Exports[I].getPointer()) &&
|
||||
"Unknown submodule!");
|
||||
Record.push_back(ExportedID);
|
||||
Record.push_back(Mod->Exports[I].getInt());
|
||||
}
|
||||
|
|
|
@ -9,8 +9,7 @@ module diamond_right {
|
|||
}
|
||||
module diamond_bottom {
|
||||
header "diamond_bottom.h"
|
||||
export diamond_left
|
||||
export diamond_right
|
||||
export *
|
||||
}
|
||||
module irgen { header "irgen.h" }
|
||||
module lookup_left_objc { header "lookup_left.h" }
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
int *A1;
|
|
@ -0,0 +1 @@
|
|||
unsigned int *A2;
|
|
@ -0,0 +1 @@
|
|||
short *B1;
|
|
@ -0,0 +1 @@
|
|||
unsigned short *B2;
|
|
@ -0,0 +1,4 @@
|
|||
__import_module__ A.One;
|
||||
__import_module__ B.One;
|
||||
|
||||
long *C1;
|
|
@ -0,0 +1,4 @@
|
|||
__import_module__ A.Two;
|
||||
__import_module__ B.Two;
|
||||
|
||||
unsigned long *C2;
|
|
@ -0,0 +1,20 @@
|
|||
module A {
|
||||
module One { header "A_one.h" }
|
||||
module Two { header "A_two.h" }
|
||||
}
|
||||
|
||||
module B {
|
||||
module One { header "B_one.h" }
|
||||
module Two { header "B_two.h" }
|
||||
}
|
||||
|
||||
module C {
|
||||
module One {
|
||||
header "C_one.h"
|
||||
export A.*
|
||||
}
|
||||
module Two {
|
||||
header "C_two.h"
|
||||
export *
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: %clang_cc1 -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/wildcard-submodule-exports %s -verify
|
||||
|
||||
__import_module__ C.One;
|
||||
|
||||
void test_C_One() {
|
||||
int *A1_ptr = A1;
|
||||
long *C1_ptr = C1;
|
||||
(void)B1; // expected-error{{use of undeclared identifier 'B1'}}
|
||||
}
|
||||
|
||||
__import_module__ C.Two;
|
||||
|
||||
void test_C_Two() {
|
||||
unsigned int *A2_ptr = A2;
|
||||
unsigned short *B2_ptr = B2;
|
||||
unsigned long *C2_ptr = C2;
|
||||
}
|
||||
|
||||
__import_module__ B.One;
|
||||
|
||||
void test_B_One() {
|
||||
short *B1_ptr = B1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue