]> granicus.if.org Git - clang/commitdiff
Detect when mapping a #include/#import over to a submodule ends up
authorDouglas Gregor <dgregor@apple.com>
Tue, 20 Dec 2011 00:28:52 +0000 (00:28 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 20 Dec 2011 00:28:52 +0000 (00:28 +0000)
hitting a submodule that was never actually created, e.g., because
that header wasn't parsed. In such cases, complain (because the
module's umbrella headers don't cover everything) and fall back to
including the header.

Later, we'll add a warning at module-build time to catch all such
cases. However, this fallback is important to eliminate assertions in
the ASTWriter when this happens.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146933 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticFrontendKinds.td
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/Module.h
lib/Frontend/CompilerInstance.cpp
lib/Lex/PPDirectives.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Modules/Inputs/Module.framework/Headers/NotInModule.h [new file with mode: 0644]
test/Modules/auto-module-import.m

index ceef843409c11396517d56d6ccfb15a225885cdb..5efba22529a73eb1fa9c22b931a4620af14e908e 100644 (file)
@@ -139,6 +139,8 @@ def err_missing_umbrella_header : Error<
 def err_no_submodule : Error<"no submodule named %0 in module '%1'">;
 def err_no_submodule_suggest : Error<
   "no submodule named %0 in module '%1'; did you mean '%2'?">;
+def warn_missing_submodule : Warning<"missing submodule '%0'">,
+  InGroup<IncompleteUmbrella>;
 def err_module_map_temp_file : Error<
   "unable to write temporary module map file '%0'">, DefaultFatal;
 }
index d9c078f8806e28779d9c7c33f1a60f202f7ca220..bb88d48b38f1e5c53eb643d663d5b754c61ff148 100644 (file)
@@ -88,6 +88,7 @@ def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">;
 def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
 def : DiagGroup<"import">;
 def IncompatiblePointerTypes : DiagGroup<"incompatible-pointer-types">;
+def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">;
 def : DiagGroup<"init-self">;
 def : DiagGroup<"inline">;
 def : DiagGroup<"int-to-pointer-cast">;
index aef2db0feda2a77f1c413185d3642924c3e7c16d..96b716e0cee81119c5c4169dc8663a05869a0046 100644 (file)
@@ -58,6 +58,9 @@ public:
   /// \brief The headers that are part of this module.
   llvm::SmallVector<const FileEntry *, 2> Headers;
   
+  /// \brief Whether this module was loaded from a module file.
+  unsigned IsFromModuleFile : 1;
+  
   /// \brief Whether this is a framework module.
   unsigned IsFramework : 1;
   
@@ -131,17 +134,18 @@ public:
   explicit Module(StringRef Name, SourceLocation DefinitionLoc,
                   bool IsFramework)
     : Name(Name), DefinitionLoc(DefinitionLoc), Parent(0), Umbrella(),
-      IsFramework(IsFramework), IsExplicit(false), InferSubmodules(false),
-      InferExplicitSubmodules(false), InferExportWildcard(false),
-      NameVisibility(Hidden) { }
+      IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(false),
+      InferSubmodules(false), InferExplicitSubmodules(false),
+      InferExportWildcard(false), NameVisibility(Hidden) { }
   
   /// \brief Construct  a new module or submodule.
   Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, 
          bool IsFramework, bool IsExplicit)
     : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), 
-      Umbrella(), IsFramework(IsFramework), IsExplicit(IsExplicit), 
-      InferSubmodules(false), InferExplicitSubmodules(false), 
-      InferExportWildcard(false),NameVisibility(Hidden) { }
+      Umbrella(), IsFromModuleFile(false), IsFramework(IsFramework), 
+      IsExplicit(IsExplicit), InferSubmodules(false), 
+      InferExplicitSubmodules(false), InferExportWildcard(false),
+      NameVisibility(Hidden) { }
   
   ~Module();
   
index 66238d0fc9fe2f26debacfd4d851099e01c41798..12d368501ce548c3bb62f267951b60cb9d581667 100644 (file)
@@ -1270,9 +1270,23 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
   
   // Make the named module visible, if it's not already part of the module
   // we are parsing.
-  if (ModuleName != getLangOpts().CurrentModule)
+  if (ModuleName != getLangOpts().CurrentModule) {
+    if (!Module->IsFromModuleFile) {
+      // We have an umbrella header or directory that doesn't actually include
+      // all of the headers within the directory it covers. Complain about
+      // this missing submodule and recover by forgetting that we ever saw
+      // this submodule.
+      // FIXME: Should we detect this at module load time? It seems fairly
+      // expensive (and rare).
+      getDiagnostics().Report(ImportLoc, diag::warn_missing_submodule)
+        << Module->getFullModuleName()
+        << SourceRange(Path.front().second, Path.back().second);
+      
+      return 0;
+    }
     ModuleManager->makeModuleVisible(Module, Visibility);
-
+  }
+  
   // If this module import was due to an inclusion directive, create an 
   // implicit import declaration to capture it in the AST.
   if (IsInclusionDirective && hasASTContext()) {
index 7c8bfd7e7cd7b2485a8d1c85b1063651ff9b4d57..4d700aef03b9aa51ae019f4be14c64585aee217b 100644 (file)
@@ -1388,11 +1388,12 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
     // If this was an #__include_macros directive, only make macros visible.
     Module::NameVisibilityKind Visibility 
       = (IncludeKind == 3)? Module::MacrosVisible : Module::AllVisible;
-    TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
-                               /*IsIncludeDirective=*/true);
+    Module *Imported
+      = TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
+                                   /*IsIncludeDirective=*/true);
     
     // If this header isn't part of the module we're building, we're done.
-    if (!BuildingImportedModule)
+    if (!BuildingImportedModule && Imported)
       return;
   }
   
index 1efc95408b37fa0bf4f06d6add8e0b224c428911..9fc2962d27cc205acb0aaecd7bb9598b936d1aa4 100644 (file)
@@ -3086,6 +3086,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
         return Failure;
       }
       
+      CurrentModule->IsFromModuleFile = true;
       CurrentModule->InferSubmodules = InferSubmodules;
       CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
       CurrentModule->InferExportWildcard = InferExportWildcard;
index 1776b97bb03c487ef3f7388f770619622c8f3b1e..6883dbe329421ee79fe52b0f217d7962c867c85c 100644 (file)
@@ -1877,7 +1877,6 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
   for (ASTContext::import_iterator I = Context->local_import_begin(),
                                 IEnd = Context->local_import_end();
        I != IEnd; ++I) {
-    assert(SubmoduleIDs.find(I->getImportedModule()) != SubmoduleIDs.end());
     if (Module *ImportedFrom
           = ModMap.inferModuleFromLocation(FullSourceLoc(I->getLocation(), 
                                                          SrcMgr))) {
diff --git a/test/Modules/Inputs/Module.framework/Headers/NotInModule.h b/test/Modules/Inputs/Module.framework/Headers/NotInModule.h
new file mode 100644 (file)
index 0000000..6b15791
--- /dev/null
@@ -0,0 +1 @@
+int not_in_module;
index 21e79687610c931c2cf88fbe29fe1bf00af565fc..d14f9e903043c4062ac3c11c847ccce711b9dec3 100644 (file)
@@ -62,3 +62,12 @@ int getModulePrivate() { return module_private; }
 int getNoUmbrellaAPrivate() { return no_umbrella_A_private; }
 
 int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-error{{use of undeclared identifier 'no_umbrella_B_private'; did you mean 'no_umbrella_A_private'?}}
+
+// Test inclusion of headers that are under an umbrella directory but
+// not actually part of the module.
+#include <Module/NotInModule.h> // expected-warning{{treating #include as an import of module 'Module.NotInModule'}} \
+  // expected-warning{{missing submodule 'Module.NotInModule'}}
+
+int getNotInModule() {
+  return not_in_module;
+}