aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-12-20 00:28:52 +0000
committerDouglas Gregor <dgregor@apple.com>2011-12-20 00:28:52 +0000
commit305dc3ebaa0bea5f3b789e4b54afc79c25907615 (patch)
treedfe626b56bee645cfac86bdb52d0c63bcd2bdb47
parent6446c3e3600032c5f17ca2324a4581b9301afa59 (diff)
Detect when mapping a #include/#import over to a submodule ends up
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
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/Module.h16
-rw-r--r--lib/Frontend/CompilerInstance.cpp18
-rw-r--r--lib/Lex/PPDirectives.cpp7
-rw-r--r--lib/Serialization/ASTReader.cpp1
-rw-r--r--lib/Serialization/ASTWriter.cpp1
-rw-r--r--test/Modules/Inputs/Module.framework/Headers/NotInModule.h1
-rw-r--r--test/Modules/auto-module-import.m9
9 files changed, 44 insertions, 12 deletions
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index ceef843409..5efba22529 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -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;
}
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index d9c078f880..bb88d48b38 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -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">;
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index aef2db0fed..96b716e0ce 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -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();
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 66238d0fc9..12d368501c 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -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()) {
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 7c8bfd7e7c..4d700aef03 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -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;
}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 1efc95408b..9fc2962d27 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -3086,6 +3086,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
return Failure;
}
+ CurrentModule->IsFromModuleFile = true;
CurrentModule->InferSubmodules = InferSubmodules;
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 1776b97bb0..6883dbe329 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -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
index 0000000000..6b15791eb2
--- /dev/null
+++ b/test/Modules/Inputs/Module.framework/Headers/NotInModule.h
@@ -0,0 +1 @@
+int not_in_module;
diff --git a/test/Modules/auto-module-import.m b/test/Modules/auto-module-import.m
index 21e7968761..d14f9e9030 100644
--- a/test/Modules/auto-module-import.m
+++ b/test/Modules/auto-module-import.m
@@ -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;
+}