diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-12-05 17:28:06 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-12-05 17:28:06 +0000 |
commit | 0adaa880993ad23186c87c7f98e7a3fd2697742c (patch) | |
tree | ad45854454861d185a11fb6dd96498f454d48441 | |
parent | 4bc8738d837e5d401235f99e55277338e20e3651 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145811 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/Module.h | 4 | ||||
-rw-r--r-- | lib/Basic/Module.cpp | 12 | ||||
-rw-r--r-- | lib/Lex/ModuleMap.cpp | 9 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 69 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 3 | ||||
-rw-r--r-- | test/Modules/Inputs/module.map | 3 | ||||
-rw-r--r-- | test/Modules/Inputs/wildcard-submodule-exports/A_one.h | 1 | ||||
-rw-r--r-- | test/Modules/Inputs/wildcard-submodule-exports/A_two.h | 1 | ||||
-rw-r--r-- | test/Modules/Inputs/wildcard-submodule-exports/B_one.h | 1 | ||||
-rw-r--r-- | test/Modules/Inputs/wildcard-submodule-exports/B_two.h | 1 | ||||
-rw-r--r-- | test/Modules/Inputs/wildcard-submodule-exports/C_one.h | 4 | ||||
-rw-r--r-- | test/Modules/Inputs/wildcard-submodule-exports/C_two.h | 4 | ||||
-rw-r--r-- | test/Modules/Inputs/wildcard-submodule-exports/module.map | 20 | ||||
-rw-r--r-- | test/Modules/wildcard-submodule-exports.cpp | 25 |
14 files changed, 143 insertions, 14 deletions
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h index 422449b6bb..af41d69adf 100644 --- a/include/clang/Basic/Module.h +++ b/include/clang/Basic/Module.h @@ -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. diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 6bca55c754..59fced5f16 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -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; diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index b20ccd122f..02848eef6d 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -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; } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 0742ec6184..8d957e2633 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -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(); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index f48d18c478..3e91e55228 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -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()); } diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index 7d8d11f957..f25a36edfb 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -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" } diff --git a/test/Modules/Inputs/wildcard-submodule-exports/A_one.h b/test/Modules/Inputs/wildcard-submodule-exports/A_one.h new file mode 100644 index 0000000000..4a2c2396ea --- /dev/null +++ b/test/Modules/Inputs/wildcard-submodule-exports/A_one.h @@ -0,0 +1 @@ +int *A1; diff --git a/test/Modules/Inputs/wildcard-submodule-exports/A_two.h b/test/Modules/Inputs/wildcard-submodule-exports/A_two.h new file mode 100644 index 0000000000..1b08599dc7 --- /dev/null +++ b/test/Modules/Inputs/wildcard-submodule-exports/A_two.h @@ -0,0 +1 @@ +unsigned int *A2; diff --git a/test/Modules/Inputs/wildcard-submodule-exports/B_one.h b/test/Modules/Inputs/wildcard-submodule-exports/B_one.h new file mode 100644 index 0000000000..0f44a564fd --- /dev/null +++ b/test/Modules/Inputs/wildcard-submodule-exports/B_one.h @@ -0,0 +1 @@ +short *B1; diff --git a/test/Modules/Inputs/wildcard-submodule-exports/B_two.h b/test/Modules/Inputs/wildcard-submodule-exports/B_two.h new file mode 100644 index 0000000000..0e51242629 --- /dev/null +++ b/test/Modules/Inputs/wildcard-submodule-exports/B_two.h @@ -0,0 +1 @@ +unsigned short *B2; diff --git a/test/Modules/Inputs/wildcard-submodule-exports/C_one.h b/test/Modules/Inputs/wildcard-submodule-exports/C_one.h new file mode 100644 index 0000000000..cbdc2beecc --- /dev/null +++ b/test/Modules/Inputs/wildcard-submodule-exports/C_one.h @@ -0,0 +1,4 @@ +__import_module__ A.One; +__import_module__ B.One; + +long *C1; diff --git a/test/Modules/Inputs/wildcard-submodule-exports/C_two.h b/test/Modules/Inputs/wildcard-submodule-exports/C_two.h new file mode 100644 index 0000000000..6a66ac7831 --- /dev/null +++ b/test/Modules/Inputs/wildcard-submodule-exports/C_two.h @@ -0,0 +1,4 @@ +__import_module__ A.Two; +__import_module__ B.Two; + +unsigned long *C2; diff --git a/test/Modules/Inputs/wildcard-submodule-exports/module.map b/test/Modules/Inputs/wildcard-submodule-exports/module.map new file mode 100644 index 0000000000..64b0d89529 --- /dev/null +++ b/test/Modules/Inputs/wildcard-submodule-exports/module.map @@ -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 * + } +} diff --git a/test/Modules/wildcard-submodule-exports.cpp b/test/Modules/wildcard-submodule-exports.cpp new file mode 100644 index 0000000000..b892acbe59 --- /dev/null +++ b/test/Modules/wildcard-submodule-exports.cpp @@ -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; +} + |