summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td10
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td17
-rw-r--r--lib/CodeGen/ObjectFilePCHContainerOperations.cpp7
-rw-r--r--lib/Frontend/CompilerInstance.cpp99
-rw-r--r--lib/Serialization/ASTReader.cpp103
-rw-r--r--test/Index/pch-depending-on-deleted-module.c2
-rw-r--r--test/Modules/dependency-gen.modulemap36
-rw-r--r--test/Modules/explicit-build-missing-files.cpp21
-rw-r--r--test/Modules/explicit-build.cpp5
-rw-r--r--test/Modules/fatal-module-loader-error.m4
-rw-r--r--test/Modules/relative-dep-gen.cpp6
12 files changed, 190 insertions, 123 deletions
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index fc3ca62113..605736f076 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -194,9 +194,8 @@ def err_unable_to_make_temp : Error<
"unable to make temporary file: %0">;
// Modules
-def err_module_file_conflict : Error<"module '%0' found in both '%1' and '%2'">;
def err_module_format_unhandled : Error<
- "no handler registered for module format '%0'">;
+ "no handler registered for module format '%0'">, DefaultFatal;
// TransformActions
// TODO: Use a custom category name to distinguish rewriter errors.
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index f4ab4800c9..21058aa0bb 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -194,16 +194,6 @@ def remark_module_build_done : Remark<"finished building module '%0'">,
def err_conflicting_module_names : Error<
"conflicting module names specified: '-fmodule-name=%0' and "
"'-fmodule-implementation-of %1'">;
-def err_conflicting_module_files : Error<
- "module '%0' is defined in both '%1' and '%2'">;
-def err_module_file_not_found : Error<
- "module file '%0' not found">, DefaultFatal;
-def err_module_file_invalid : Error<
- "file '%0' is not a valid precompiled module file">, DefaultFatal;
-def note_module_file_imported_by : Note<
- "imported by %select{|module '%2' in }1'%0'">;
-def err_module_file_not_module : Error<
- "AST file '%0' was not built as a module">, DefaultFatal;
def err_missing_vfs_overlay_file : Error<
"virtual filesystem overlay file '%0' not found">, DefaultFatal;
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index 796027ea62..bd81c8041f 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -53,6 +53,20 @@ def err_pch_different_branch : Error<
def err_pch_with_compiler_errors : Error<
"PCH file contains compiler errors">;
+def err_module_file_conflict : Error<
+ "module '%0' is defined in both '%1' and '%2'">, DefaultFatal;
+def err_module_file_not_found : Error<
+ "%select{PCH|module|AST}0 file '%1' not found%select{|: %3}2">, DefaultFatal;
+def err_module_file_out_of_date : Error<
+ "%select{PCH|module|AST}0 file '%1' is out of date and "
+ "needs to be rebuilt%select{|: %3}2">, DefaultFatal;
+def err_module_file_invalid : Error<
+ "file '%1' is not a valid precompiled %select{PCH|module|AST}0 file">, DefaultFatal;
+def note_module_file_imported_by : Note<
+ "imported by %select{|module '%2' in }1'%0'">;
+def err_module_file_not_module : Error<
+ "AST file '%0' was not built as a module">, DefaultFatal;
+
def err_imported_module_not_found : Error<
"module '%0' in AST file '%1' (imported by AST file '%2') "
"is not defined in any loaded module map file; "
@@ -82,9 +96,6 @@ def err_pch_pp_detailed_record : Error<
"'-detailed-preprocessing-record' but %select{precompiled header was not "
"built with it|it is not present on the command line}0">;
-def err_not_a_pch_file : Error<
- "'%0' does not appear to be a precompiled header file">, DefaultFatal;
-
def err_module_odr_violation_missing_decl : Error<
"%q0 from module '%1' is not present in definition of %q2"
"%select{ in module '%4'| provided earlier}3">, NoSFINAE;
diff --git a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index e09b2857a3..d0e857be3c 100644
--- a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -58,7 +58,7 @@ public:
const std::string &OutputFileName,
raw_pwrite_stream *OS,
std::shared_ptr<PCHBuffer> Buffer)
- : Diags(diags), HeaderSearchOpts(HSO), PreprocessorOpts(PPO),
+ : Diags(diags), Ctx(nullptr), HeaderSearchOpts(HSO), PreprocessorOpts(PPO),
TargetOpts(TO), LangOpts(LO), OS(OS), Buffer(Buffer) {
// The debug info output isn't affected by CodeModel and
// ThreadModel, but the backend expects them to be nonempty.
@@ -71,6 +71,11 @@ public:
virtual ~PCHContainerGenerator() {}
void Initialize(ASTContext &Context) override {
+ if (Ctx) {
+ assert(Ctx == &Context);
+ return;
+ }
+
Ctx = &Context;
VMContext.reset(new llvm::LLVMContext());
M.reset(new llvm::Module(MainFileName, *VMContext));
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 5133ffc272..7d9efd4e9b 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -1261,8 +1261,10 @@ void CompilerInstance::createModuleManager() {
getASTContext().setExternalSource(ModuleManager);
if (hasSema())
ModuleManager->InitializeSema(getSema());
- if (hasASTConsumer())
+ if (hasASTConsumer()) {
+ getASTConsumer().Initialize(getASTContext());
ModuleManager->StartTranslationUnit(&getASTConsumer());
+ }
if (TheDependencyFileGenerator)
TheDependencyFileGenerator->AttachToASTReader(*ModuleManager);
@@ -1284,86 +1286,44 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
// the files we were handed.
struct ReadModuleNames : ASTReaderListener {
CompilerInstance &CI;
- std::vector<StringRef> ModuleFileStack;
- std::vector<StringRef> ModuleNameStack;
- bool Failed;
- bool TopFileIsModule;
-
- ReadModuleNames(CompilerInstance &CI)
- : CI(CI), Failed(false), TopFileIsModule(false) {}
-
- bool needsImportVisitation() const override { return true; }
+ llvm::SmallVector<IdentifierInfo*, 8> LoadedModules;
- void visitImport(StringRef FileName) override {
- if (!CI.ExplicitlyLoadedModuleFiles.insert(FileName).second) {
- if (ModuleFileStack.size() == 0)
- TopFileIsModule = true;
- return;
- }
+ ReadModuleNames(CompilerInstance &CI) : CI(CI) {}
- ModuleFileStack.push_back(FileName);
- ModuleNameStack.push_back(StringRef());
- if (ASTReader::readASTFileControlBlock(FileName, CI.getFileManager(),
- CI.getPCHContainerReader(),
- *this)) {
- CI.getDiagnostics().Report(
- SourceLocation(), CI.getFileManager().getBufferForFile(FileName)
- ? diag::err_module_file_invalid
- : diag::err_module_file_not_found)
- << FileName;
- for (int I = ModuleFileStack.size() - 2; I >= 0; --I)
- CI.getDiagnostics().Report(SourceLocation(),
- diag::note_module_file_imported_by)
- << ModuleFileStack[I]
- << !ModuleNameStack[I].empty() << ModuleNameStack[I];
- Failed = true;
- }
- ModuleNameStack.pop_back();
- ModuleFileStack.pop_back();
+ void ReadModuleName(StringRef ModuleName) override {
+ LoadedModules.push_back(
+ CI.getPreprocessor().getIdentifierInfo(ModuleName));
}
- void ReadModuleName(StringRef ModuleName) override {
- if (ModuleFileStack.size() == 1)
- TopFileIsModule = true;
- ModuleNameStack.back() = ModuleName;
-
- auto &ModuleFile = CI.ModuleFileOverrides[ModuleName];
- if (!ModuleFile.empty() &&
- CI.getFileManager().getFile(ModuleFile) !=
- CI.getFileManager().getFile(ModuleFileStack.back()))
- CI.getDiagnostics().Report(SourceLocation(),
- diag::err_conflicting_module_files)
- << ModuleName << ModuleFile << ModuleFileStack.back();
- ModuleFile = ModuleFileStack.back();
+ void registerAll() {
+ for (auto *II : LoadedModules) {
+ CI.KnownModules[II] = CI.getPreprocessor()
+ .getHeaderSearchInfo()
+ .getModuleMap()
+ .findModule(II->getName());
+ }
+ LoadedModules.clear();
}
- } RMN(*this);
+ };
// If we don't already have an ASTReader, create one now.
if (!ModuleManager)
createModuleManager();
- // Tell the module manager about this module file.
- if (getModuleManager()->getModuleManager().addKnownModuleFile(FileName)) {
- getDiagnostics().Report(SourceLocation(), diag::err_module_file_not_found)
- << FileName;
- return false;
- }
-
- // Build our mapping of module names to module files from this file
- // and its imports.
- RMN.visitImport(FileName);
-
- if (RMN.Failed)
- return false;
+ auto Listener = llvm::make_unique<ReadModuleNames>(*this);
+ auto &ListenerRef = *Listener;
+ ASTReader::ListenerScope ReadModuleNamesListener(*ModuleManager,
+ std::move(Listener));
- // If we never found a module name for the top file, then it's not a module,
- // it's a PCH or preamble or something.
- if (!RMN.TopFileIsModule) {
- getDiagnostics().Report(SourceLocation(), diag::err_module_file_not_module)
- << FileName;
+ // Try to load the module file.
+ if (ModuleManager->ReadAST(FileName, serialization::MK_ExplicitModule,
+ SourceLocation(), ASTReader::ARR_None)
+ != ASTReader::Success)
return false;
- }
+ // We successfully loaded the module file; remember the set of provided
+ // modules so that we don't try to load implicit modules for them.
+ ListenerRef.registerAll();
return true;
}
@@ -1412,6 +1372,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return ModuleLoadResult();
}
+ // FIXME: Rmove ModuleFileOverrides
auto Override = ModuleFileOverrides.find(ModuleName);
bool Explicit = Override != ModuleFileOverrides.end();
@@ -1507,7 +1468,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
case ASTReader::ConfigurationMismatch:
case ASTReader::HadErrors:
ModuleLoader::HadFatalFailure = true;
- // FIXME: The ASTReader will already have complained, but can we showhorn
+ // FIXME: The ASTReader will already have complained, but can we shoehorn
// that diagnostic information into a more useful form?
KnownModules[Path[0].first] = nullptr;
return ModuleLoadResult();
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index ff771fd00a..29a935c909 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -2029,6 +2029,21 @@ void ASTReader::ResolveImportedPath(std::string &Filename, StringRef Prefix) {
Filename.assign(Buffer.begin(), Buffer.end());
}
+static bool isDiagnosedResult(ASTReader::ASTReadResult ARR, unsigned Caps) {
+ switch (ARR) {
+ case ASTReader::Failure: return true;
+ case ASTReader::Missing: return !(Caps & ASTReader::ARR_Missing);
+ case ASTReader::OutOfDate: return !(Caps & ASTReader::ARR_OutOfDate);
+ case ASTReader::VersionMismatch: return !(Caps & ASTReader::ARR_VersionMismatch);
+ case ASTReader::ConfigurationMismatch:
+ return !(Caps & ASTReader::ARR_ConfigurationMismatch);
+ case ASTReader::HadErrors: return true;
+ case ASTReader::Success: return false;
+ }
+
+ llvm_unreachable("unknown ASTReadResult");
+}
+
ASTReader::ASTReadResult
ASTReader::ReadControlBlock(ModuleFile &F,
SmallVectorImpl<ImportedModule> &Loaded,
@@ -2064,8 +2079,9 @@ ASTReader::ReadControlBlock(ModuleFile &F,
PP.getHeaderSearchInfo().getHeaderSearchOpts();
// All user input files reside at the index range [0, NumUserInputs), and
- // system input files reside at [NumUserInputs, NumInputs).
- if (!DisableValidation) {
+ // system input files reside at [NumUserInputs, NumInputs). For explicitly
+ // loaded module files, ignore missing inputs.
+ if (!DisableValidation && F.Kind != MK_ExplicitModule) {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
// If we are reading a module, we will create a verification timestamp,
@@ -2181,10 +2197,23 @@ ASTReader::ReadControlBlock(ModuleFile &F,
ASTFileSignature StoredSignature = Record[Idx++];
auto ImportedFile = ReadPath(F, Record, Idx);
+ // If our client can't cope with us being out of date, we can't cope with
+ // our dependency being missing.
+ unsigned Capabilities = ClientLoadCapabilities;
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Capabilities &= ~ARR_Missing;
+
// Load the AST file.
- switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
- StoredSize, StoredModTime, StoredSignature,
- ClientLoadCapabilities)) {
+ auto Result = ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F,
+ Loaded, StoredSize, StoredModTime,
+ StoredSignature, Capabilities);
+
+ // If we diagnosed a problem, produce a backtrace.
+ if (isDiagnosedResult(Result, Capabilities))
+ Diag(diag::note_module_file_imported_by)
+ << F.FileName << !F.ModuleName.empty() << F.ModuleName;
+
+ switch (Result) {
case Failure: return Failure;
// If we have to ignore the dependency, we'll have to ignore this too.
case Missing:
@@ -3152,11 +3181,18 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr;
if (!ModMap) {
assert(ImportedBy && "top-level import should be verified");
- if ((ClientLoadCapabilities & ARR_Missing) == 0)
- Diag(diag::err_imported_module_not_found) << F.ModuleName << F.FileName
- << ImportedBy->FileName
- << F.ModuleMapPath;
- return Missing;
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) {
+ if (auto *ASTFE = M ? M->getASTFile() : nullptr)
+ // This module was defined by an imported (explicit) module.
+ Diag(diag::err_module_file_conflict) << F.ModuleName << F.FileName
+ << ASTFE->getName();
+ else
+ // This module was built with a different module map.
+ Diag(diag::err_imported_module_not_found)
+ << F.ModuleName << F.FileName << ImportedBy->FileName
+ << F.ModuleMapPath;
+ }
+ return OutOfDate;
}
assert(M->Name == F.ModuleName && "found module with different name");
@@ -3557,6 +3593,20 @@ static bool startsWithASTFileMagic(BitstreamCursor &Stream) {
Stream.Read(8) == 'H';
}
+static unsigned moduleKindForDiagnostic(ModuleKind Kind) {
+ switch (Kind) {
+ case MK_PCH:
+ return 0; // PCH
+ case MK_ImplicitModule:
+ case MK_ExplicitModule:
+ return 1; // module
+ case MK_MainFile:
+ case MK_Preamble:
+ return 2; // main source file
+ }
+ llvm_unreachable("unknown module kind");
+}
+
ASTReader::ASTReadResult
ASTReader::ReadASTCore(StringRef FileName,
ModuleKind Type,
@@ -3589,11 +3639,9 @@ ASTReader::ReadASTCore(StringRef FileName,
return Missing;
// Otherwise, return an error.
- {
- std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
- + ErrorStr;
- Error(Msg);
- }
+ Diag(diag::err_module_file_not_found) << moduleKindForDiagnostic(Type)
+ << FileName << ErrorStr.empty()
+ << ErrorStr;
return Failure;
case ModuleManager::OutOfDate:
@@ -3603,11 +3651,9 @@ ASTReader::ReadASTCore(StringRef FileName,
return OutOfDate;
// Otherwise, return an error.
- {
- std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
- + ErrorStr;
- Error(Msg);
- }
+ Diag(diag::err_module_file_out_of_date) << moduleKindForDiagnostic(Type)
+ << FileName << ErrorStr.empty()
+ << ErrorStr;
return Failure;
}
@@ -3628,7 +3674,8 @@ ASTReader::ReadASTCore(StringRef FileName,
// Sniff for the signature.
if (!startsWithASTFileMagic(Stream)) {
- Diag(diag::err_not_a_pch_file) << FileName;
+ Diag(diag::err_module_file_invalid) << moduleKindForDiagnostic(Type)
+ << FileName;
return Failure;
}
@@ -3661,6 +3708,18 @@ ASTReader::ReadASTCore(StringRef FileName,
HaveReadControlBlock = true;
switch (ReadControlBlock(F, Loaded, ImportedBy, ClientLoadCapabilities)) {
case Success:
+ // Check that we didn't try to load a non-module AST file as a module.
+ //
+ // FIXME: Should we also perform the converse check? Loading a module as
+ // a PCH file sort of works, but it's a bit wonky.
+ if ((Type == MK_ImplicitModule || Type == MK_ExplicitModule) &&
+ F.ModuleName.empty()) {
+ auto Result = (Type == MK_ImplicitModule) ? OutOfDate : Failure;
+ if (Result != OutOfDate ||
+ (ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_module_file_not_module) << FileName;
+ return Result;
+ }
break;
case Failure: return Failure;
@@ -3690,8 +3749,6 @@ ASTReader::ReadASTCore(StringRef FileName,
break;
}
}
-
- return Success;
}
void ASTReader::InitializeContext() {
diff --git a/test/Index/pch-depending-on-deleted-module.c b/test/Index/pch-depending-on-deleted-module.c
index a0fbaf559f..8efa66a323 100644
--- a/test/Index/pch-depending-on-deleted-module.c
+++ b/test/Index/pch-depending-on-deleted-module.c
@@ -9,6 +9,6 @@
// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -I %S/Inputs/Headers -verify-pch %t/use_LibA.pch 2>&1 | FileCheck -check-prefix=VERIFY %s
// RUN: not c-index-test -test-load-source all -x c -fmodules -fimplicit-module-maps -Xclang -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -I %S/Inputs/Headers -include-pch %t/use_LibA.pch %s 2>&1 | FileCheck -check-prefix=INDEX %s
-// VERIFY: fatal error: malformed or corrupted AST file: 'Unable to load module
+// VERIFY: fatal error: module file '{{.*}}LibA.pcm' not found
// INDEX: {{^}}Failure: AST deserialization error occurred{{$}}
diff --git a/test/Modules/dependency-gen.modulemap b/test/Modules/dependency-gen.modulemap
index ba109c2be4..ace1177a3e 100644
--- a/test/Modules/dependency-gen.modulemap
+++ b/test/Modules/dependency-gen.modulemap
@@ -1,10 +1,10 @@
// RUN: cd %S
// RUN: rm -rf %t
//
-// RUN: %clang_cc1 -I. -x c++ -fmodule-name=test -fmodules -emit-module -fno-validate-pch -fmodules-strict-decluse %s -dependency-file - -MT implicit.pcm -o %t/implicit.pcm -fmodules-cache-path=%t -fmodule-map-file-home-is-cwd | FileCheck %s
+// RUN: %clang_cc1 -I. -x c++ -fmodule-name=test -fmodules -emit-module -fno-validate-pch -fmodules-strict-decluse %s -dependency-file - -MT implicit.pcm -o %t/implicit.pcm -fmodules-cache-path=%t -fmodule-map-file-home-is-cwd | FileCheck %s --check-prefix=IMPLICIT
//
// RUN: %clang_cc1 -I. -x c++ -fmodule-name=test-base -fmodules -emit-module -fno-validate-pch -fmodules-strict-decluse Inputs/dependency-gen-base.modulemap -o %t/base.pcm -fmodule-map-file-home-is-cwd
-// RUN: %clang_cc1 -I. -x c++ -fmodule-name=test -fmodules -emit-module -fno-validate-pch -fmodules-strict-decluse -fmodule-file=%t/base.pcm %s -dependency-file - -MT explicit.pcm -o %t/explicit.pcm -fmodules-cache-path=%t -fmodule-map-file-home-is-cwd | FileCheck %s
+// RUN: %clang_cc1 -I. -x c++ -fmodule-name=test -fmodules -emit-module -fno-validate-pch -fmodules-strict-decluse -fmodule-file=%t/base.pcm %s -dependency-file - -MT explicit.pcm -o %t/explicit.pcm -fmodules-cache-path=%t -fmodule-map-file-home-is-cwd | FileCheck %s --check-prefix=EXPLICIT
module "test" {
export *
header "Inputs/dependency-gen.h"
@@ -14,10 +14,30 @@ module "test" {
extern module "test-base2" "Inputs/dependency-gen-base2.modulemap"
extern module "test-base" "Inputs/dependency-gen-base.modulemap"
-// CHECK-DAG: {{[/\\]}}dependency-gen.modulemap
-// CHECK-DAG: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen-base.modulemap
-// CHECK-DAG: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen-base2.modulemap
+// For implicit use of a module via the module cache, the input files
+// referenced by the .pcm are also dependencies of this build.
+//
+// IMPLICIT-DAG: {{[/\\]}}dependency-gen.modulemap
+// IMPLICIT-DAG: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen-base.modulemap
+// IMPLICIT-DAG: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen-base2.modulemap
+// IMPLICIT-DAG: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen.h
+// IMPLICIT-DAG: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen-included.h
+// IMPLICIT-DAG: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen-included2.h
-// CHECK-DAG: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen.h
-// CHECK-DAG: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen-included.h
-// CHECK-DAG: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen-included2.h
+// For an explicit use of a module via -fmodule-file=, the other module maps
+// and included headers are not dependencies of this target (they are instead
+// dependencies of the explicitly-specified .pcm input).
+//
+// FIXME: We should avoid loading the other referenced module maps (we already
+// have a parsed copy of their contents from the .pcm file) and thus not list
+// them here.
+//
+// FIXME: We should list a dependency on the explicitly specified .pcm files
+// (whether or not -module-file-deps is specified on the command line).
+//
+// EXPLICIT-FIXME-NOT: dependency-gen-
+// EXPLICIT-FIXME: {{.*}}/base.pcm
+//
+// EXPLICIT: {{^}}explicit.pcm:
+// EXPLICIT: {{.*}}/dependency-gen.modulemap
+// EXPLICIT: {{ |\.[/\\]}}Inputs{{[/\\]}}dependency-gen.h
diff --git a/test/Modules/explicit-build-missing-files.cpp b/test/Modules/explicit-build-missing-files.cpp
new file mode 100644
index 0000000000..2ea157b934
--- /dev/null
+++ b/test/Modules/explicit-build-missing-files.cpp
@@ -0,0 +1,21 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo 'extern int a;' > %t/a.h
+// RUN: echo 'extern int b;' > %t/b.h
+// RUN: echo 'module a { header "a.h" header "b.h" }' > %t/modulemap
+
+// We lazily check that the files referenced by an explicitly-specified .pcm
+// file exist. Test this by removing files and ensuring that the compilation
+// still succeeds.
+//
+// RUN: %clang_cc1 -fmodules -I %t -emit-module -fmodule-name=a -x c++ %t/modulemap -o %t/a.pcm
+// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
+// RUN: rm %t/modulemap
+// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
+// RUN: rm %t/b.h
+// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s
+// RUN: rm %t/a.h
+// RUN: %clang_cc1 -fmodules -I %t -fmodule-file=%t/a.pcm %s -verify
+
+#include "a.h" // expected-error {{file not found}}
+int x = b;
diff --git a/test/Modules/explicit-build.cpp b/test/Modules/explicit-build.cpp
index 01aa5dc68b..4f12581055 100644
--- a/test/Modules/explicit-build.cpp
+++ b/test/Modules/explicit-build.cpp
@@ -179,6 +179,7 @@
// CHECK-NO-FILE-INDIRECT: error: module file '{{.*}}a.pcm' not found
// CHECK-NO-FILE-INDIRECT-NEXT: note: imported by module 'b' in '{{.*}}b.pcm'
// CHECK-NO-FILE-INDIRECT-NEXT: note: imported by module 'c' in '{{.*}}c.pcm'
+// CHECK-NO-FILE-INDIRECT-NOT: note:
// -------------------------------
// Check that we don't get upset if B's timestamp is newer than C's.
@@ -198,4 +199,6 @@
// RUN: -fmodule-file=%t/c.pcm \
// RUN: %s -DHAVE_A -DHAVE_B -DHAVE_C 2>&1 | FileCheck --check-prefix=CHECK-MISMATCHED-B %s
//
-// CHECK-MISMATCHED-B: fatal error: malformed or corrupted AST file: {{.*}}b.pcm": module file out of date
+// CHECK-MISMATCHED-B: fatal error: module file '{{.*}}b.pcm' is out of date and needs to be rebuilt
+// CHECK-MISMATCHED-B-NEXT: note: imported by module 'c'
+// CHECK-MISMATCHED-B-NOT: note:
diff --git a/test/Modules/fatal-module-loader-error.m b/test/Modules/fatal-module-loader-error.m
index 99a42c2aff..6e6131e000 100644
--- a/test/Modules/fatal-module-loader-error.m
+++ b/test/Modules/fatal-module-loader-error.m
@@ -8,13 +8,13 @@
#ifdef IMPLICIT
-// expected-error@+1{{does not appear to be}}
+// expected-error@+1{{Module.pcm' is not a valid precompiled module file}}
#import <Module/Module.h>
#pragma clang __debug crash;
#else
-// expected-error@+1{{does not appear to be}}
+// expected-error@+1{{Module.pcm' is not a valid precompiled module file}}
@import Module;
#pragma clang __debug crash;
diff --git a/test/Modules/relative-dep-gen.cpp b/test/Modules/relative-dep-gen.cpp
index 5fbfcfa381..d82b5a18b1 100644
--- a/test/Modules/relative-dep-gen.cpp
+++ b/test/Modules/relative-dep-gen.cpp
@@ -25,6 +25,6 @@
// CHECK-BUILD: Inputs/relative-dep-gen-1.h
// CHECK-BUILD: Inputs/relative-dep-gen-2.h
// CHECK-USE: use.o:
-// CHECK-USE: Inputs/relative-dep-gen{{(-cwd)?}}.modulemap
-// CHECK-USE: relative-dep-gen.cpp
-// CHECK-USE: Inputs/relative-dep-gen-1.h
+// CHECK-USE-DAG: Inputs/relative-dep-gen{{(-cwd)?}}.modulemap
+// CHECK-USE-DAG: relative-dep-gen.cpp
+// CHECK-USE-DAG: Inputs/relative-dep-gen-1.h