]> granicus.if.org Git - clang/commitdiff
Implement support for wildcard exports in modules, allowing a module
authorDouglas Gregor <dgregor@apple.com>
Mon, 5 Dec 2011 17:28:06 +0000 (17:28 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 5 Dec 2011 17:28:06 +0000 (17:28 +0000)
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

14 files changed:
include/clang/Basic/Module.h
lib/Basic/Module.cpp
lib/Lex/ModuleMap.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Modules/Inputs/module.map
test/Modules/Inputs/wildcard-submodule-exports/A_one.h [new file with mode: 0644]
test/Modules/Inputs/wildcard-submodule-exports/A_two.h [new file with mode: 0644]
test/Modules/Inputs/wildcard-submodule-exports/B_one.h [new file with mode: 0644]
test/Modules/Inputs/wildcard-submodule-exports/B_two.h [new file with mode: 0644]
test/Modules/Inputs/wildcard-submodule-exports/C_one.h [new file with mode: 0644]
test/Modules/Inputs/wildcard-submodule-exports/C_two.h [new file with mode: 0644]
test/Modules/Inputs/wildcard-submodule-exports/module.map [new file with mode: 0644]
test/Modules/wildcard-submodule-exports.cpp [new file with mode: 0644]

index 422449b6bb9ea6bdfe1ef500bedaa1bcbc46b332..af41d69adf10645dc56d70d1eec9c584eb6d8b44 100644 (file)
@@ -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.
index 6bca55c754a8f09bd4dcfcd5859bd5461b00c38e..59fced5f16cd1dcc878c7b3a7df61dbda58c54fc 100644 (file)
@@ -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;
   
index b20ccd122f541d70157460f3c055b5542f0fa900..02848eef6d44d8a8c7f878d028b9d43aeb0df661 100644 (file)
@@ -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;
     }
     
index 0742ec61842778eab0fd6aa19d9b7f7fce688de9..8d957e26335b1a170368e0ba75ae234a4d5e73a7 100644 (file)
@@ -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();
   
index f48d18c478a2e682a847b2a1706a0c3108460937..3e91e55228ef28d9ce4e616ed19b26703d331c8f 100644 (file)
@@ -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());
       }
index 7d8d11f9579319a5645edf39ceaee37b7f2de8f9..f25a36edfbd115b66649ac284b57d27147d3c5cb 100644 (file)
@@ -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 (file)
index 0000000..4a2c239
--- /dev/null
@@ -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 (file)
index 0000000..1b08599
--- /dev/null
@@ -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 (file)
index 0000000..0f44a56
--- /dev/null
@@ -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 (file)
index 0000000..0e51242
--- /dev/null
@@ -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 (file)
index 0000000..cbdc2be
--- /dev/null
@@ -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 (file)
index 0000000..6a66ac7
--- /dev/null
@@ -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 (file)
index 0000000..64b0d89
--- /dev/null
@@ -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 (file)
index 0000000..b892acb
--- /dev/null
@@ -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;
+}
+