Don't build modules with (submodules with) missing headers

Unless they are in submodules that aren't available anyway, due to
requirements not being met.  Also, mark children as unavailable when the
parent is.

llvm-svn: 206664
This commit is contained in:
Ben Langmuir 2014-04-18 22:07:31 +00:00
parent b5d368e838
commit ec8c975214
7 changed files with 48 additions and 10 deletions

View File

@ -123,8 +123,13 @@ public:
/// will be false to indicate that this (sub)module is not available. /// will be false to indicate that this (sub)module is not available.
SmallVector<Requirement, 2> Requirements; SmallVector<Requirement, 2> Requirements;
/// \brief Whether this module is available in the current /// \brief Whether this module is missing a feature from \c Requirements.
/// translation unit. unsigned IsMissingRequirement : 1;
/// \brief Whether this module is available in the current translation unit.
///
/// If the module is missing headers or does not meet all requirements then
/// this bit will be 0.
unsigned IsAvailable : 1; unsigned IsAvailable : 1;
/// \brief Whether this module was loaded from a module file. /// \brief Whether this module was loaded from a module file.
@ -407,6 +412,9 @@ public:
const LangOptions &LangOpts, const LangOptions &LangOpts,
const TargetInfo &Target); const TargetInfo &Target);
/// \brief Mark this module and all of its submodules as unavailable.
void markUnavailable();
/// \brief Find the submodule with the given name. /// \brief Find the submodule with the given name.
/// ///
/// \returns The submodule if found, or NULL otherwise. /// \returns The submodule if found, or NULL otherwise.

View File

@ -160,6 +160,11 @@ void Module::addRequirement(StringRef Feature, bool RequiredState,
if (hasFeature(Feature, LangOpts, Target) == RequiredState) if (hasFeature(Feature, LangOpts, Target) == RequiredState)
return; return;
IsMissingRequirement = true;
markUnavailable();
}
void Module::markUnavailable() {
if (!IsAvailable) if (!IsAvailable)
return; return;

View File

@ -288,7 +288,8 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement, if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
MissingHeader)) { MissingHeader)) {
if (MissingHeader.FileNameLoc.isValid()) { if (MissingHeader.FileNameLoc.isValid()) {
CI.getDiagnostics().Report(diag::err_module_header_missing) CI.getDiagnostics().Report(MissingHeader.FileNameLoc,
diag::err_module_header_missing)
<< MissingHeader.IsUmbrella << MissingHeader.FileName; << MissingHeader.IsUmbrella << MissingHeader.FileName;
} else { } else {
CI.getDiagnostics().Report(diag::err_module_unavailable) CI.getDiagnostics().Report(diag::err_module_unavailable)

View File

@ -1477,6 +1477,15 @@ void ModuleMapParser::parseModuleDecl() {
inferFrameworkLink(ActiveModule, Directory, SourceMgr.getFileManager()); inferFrameworkLink(ActiveModule, Directory, SourceMgr.getFileManager());
} }
// If the module meets all requirements but is still unavailable, mark the
// whole tree as unavailable to prevent it from building.
if (!ActiveModule->IsAvailable && !ActiveModule->IsMissingRequirement &&
ActiveModule->Parent) {
ActiveModule->getTopLevelModule()->markUnavailable();
ActiveModule->getTopLevelModule()->MissingHeaders.append(
ActiveModule->MissingHeaders.begin(), ActiveModule->MissingHeaders.end());
}
// We're done parsing this module. Pop back to the previous module. // We're done parsing this module. Pop back to the previous module.
ActiveModule = PreviousActiveModule; ActiveModule = PreviousActiveModule;
} }
@ -1705,9 +1714,8 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
// If we find a module that has a missing header, we mark this module as // If we find a module that has a missing header, we mark this module as
// unavailable and store the header directive for displaying diagnostics. // unavailable and store the header directive for displaying diagnostics.
// Other submodules in the same module can still be used.
Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword; Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
ActiveModule->IsAvailable = false; ActiveModule->markUnavailable();
ActiveModule->MissingHeaders.push_back(Header); ActiveModule->MissingHeaders.push_back(Header);
} }
} }

View File

@ -15,3 +15,11 @@ module missing_headers {
module missing { header "missing.h" } module missing { header "missing.h" }
module not_missing { header "not_missing.h" } module not_missing { header "not_missing.h" }
} }
module missing_unavailable_headers {
module missing {
requires !objc
header "missing.h"
}
module not_missing { }
}

View File

@ -0,0 +1,13 @@
// RUN: rm -rf %t
// RUN: not %clang_cc1 -x objective-c -fmodules-cache-path=%t -fmodules -I %S/Inputs/submodules %s 2>&1 | FileCheck %s
// FIXME: cannot use -verify, because the error from inside the module build has
// a different source manager than the verifier.
@import missing_unavailable_headers; // OK
@import missing_unavailable_headers.not_missing; // OK
// CHECK-NOT: missing_unavailable_headers
@import missing_headers;
// CHECK: module.map:15:27: error: header 'missing.h' not found
// CHECK: could not build module 'missing_headers'

View File

@ -32,8 +32,3 @@ extern MyTypeA import_self_test_a; // expected-error {{must be imported from mod
// expected-note@import-self-a.h:1 {{here}} // expected-note@import-self-a.h:1 {{here}}
extern MyTypeC import_self_test_c; extern MyTypeC import_self_test_c;
extern MyTypeD import_self_test_d; extern MyTypeD import_self_test_d;
// expected-error@Inputs/submodules/module.map:15{{header 'missing.h' not found}}
@import missing_headers.missing;
@import missing_headers.not_missing;
void f() { NotMissingFunction(); };