From: Richard Smith Date: Mon, 27 Oct 2014 23:01:16 +0000 (+0000) Subject: [modules] Load .pcm files specified by -fmodule-file lazily. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=489c8c9c1cca423484ad299d96c294096abf5dff;p=clang [modules] Load .pcm files specified by -fmodule-file lazily. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@220731 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 0f35ae4373..15f74b1169 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -190,8 +190,10 @@ 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_module_already_loaded : Error< - "module '%0' has already been loaded; cannot load module file '%1'">; +def err_conflicting_module_files : Error< + "module '%0' is defined in both '%1' and '%2'">; +def err_module_file_not_found : Error< + "file '%0' is not a precompiled module file">, DefaultFatal; def err_module_file_not_module : Error< "AST file '%0' was not built as a module">, DefaultFatal; diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index 6f15331e8f..31a0d098a2 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -117,7 +117,10 @@ class CompilerInstance : public ModuleLoader { /// \brief The set of top-level modules that has already been loaded, /// along with the module map llvm::DenseMap KnownModules; - + + /// \brief Module names that have an override for the target file. + llvm::StringMap ModuleFileOverrides; + /// \brief The location of the module-import keyword for the last module /// import. SourceLocation LastModuleImportLoc; @@ -691,7 +694,7 @@ public: // Create module manager. void createModuleManager(); - ModuleLoadResult loadModuleFile(StringRef FileName, SourceLocation Loc); + bool loadModuleFile(StringRef FileName); ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, Module::NameVisibilityKind Visibility, diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index d967ec8d21..0891b55f81 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -193,6 +193,13 @@ public: bool isOverridden) { return true; } + + /// \brief Returns true if this \c ASTReaderListener wants to receive the + /// imports of the AST file via \c visitImport, false otherwise. + virtual bool needsImportVisitation() const { return false; } + /// \brief If needsImportVisitation returns \c true, this is called for each + /// AST file imported by this AST file. + virtual void visitImport(StringRef Filename) {} }; /// \brief Simple wrapper class for chaining listeners. diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 03ab20b083..366884ec77 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -1257,51 +1257,61 @@ void CompilerInstance::createModuleManager() { } } -ModuleLoadResult -CompilerInstance::loadModuleFile(StringRef FileName, SourceLocation Loc) { - if (!ModuleManager) - createModuleManager(); - if (!ModuleManager) - return ModuleLoadResult(); +bool CompilerInstance::loadModuleFile(StringRef FileName) { + // Helper to recursively read the module names for all modules we're adding. + // We mark these as known and redirect any attempt to load that module to + // the files we were handed. + struct ReadModuleNames : ASTReaderListener { + CompilerInstance &CI; + std::vector ModuleFileStack; + bool Failed; + bool TopFileIsModule; + + ReadModuleNames(CompilerInstance &CI) + : CI(CI), Failed(false), TopFileIsModule(false) {} + + bool needsImportVisitation() const override { return true; } + + void visitImport(StringRef FileName) override { + ModuleFileStack.push_back(FileName); + if (ASTReader::readASTFileControlBlock(FileName, CI.getFileManager(), + *this)) { + CI.getDiagnostics().Report(SourceLocation(), + diag::err_module_file_not_found) + << FileName; + // FIXME: Produce a note stack explaining how we got here. + Failed = true; + } + ModuleFileStack.pop_back(); + } - // Load the module if this is the first time we've been told about this file. - auto *MF = ModuleManager->getModuleManager().lookup(FileName); - if (!MF) { - struct ReadModuleNameListener : ASTReaderListener { - std::function OnRead; - ReadModuleNameListener(std::function F) : OnRead(F) {} - void ReadModuleName(StringRef ModuleName) override { OnRead(ModuleName); } - }; - - // Register listener to track the modules that are loaded by explicitly - // loading a module file. We suppress any attempts to implicitly load - // module files for any such module. - ASTReader::ListenerScope OnReadModuleName( - *ModuleManager, - llvm::make_unique([&](StringRef ModuleName) { - auto &PP = getPreprocessor(); - auto *NameII = PP.getIdentifierInfo(ModuleName); - auto *Module = PP.getHeaderSearchInfo().lookupModule(ModuleName, false); - if (!KnownModules.insert(std::make_pair(NameII, Module)).second) - getDiagnostics().Report(Loc, diag::err_module_already_loaded) - << ModuleName << FileName; - })); - - if (ModuleManager->ReadAST(FileName, serialization::MK_ExplicitModule, Loc, - ASTReader::ARR_None) != ASTReader::Success) - return ModuleLoadResult(); + void ReadModuleName(StringRef ModuleName) override { + if (ModuleFileStack.size() == 1) + TopFileIsModule = true; - MF = ModuleManager->getModuleManager().lookup(FileName); - assert(MF && "unexpectedly failed to load module file"); - } + auto &ModuleFile = CI.ModuleFileOverrides[ModuleName]; + if (!ModuleFile.empty() && ModuleFile != ModuleFileStack.back()) + CI.getDiagnostics().Report(SourceLocation(), + diag::err_conflicting_module_files) + << ModuleName << ModuleFile << ModuleFileStack.back(); + ModuleFile = ModuleFileStack.back(); + } + } RMN(*this); + + RMN.visitImport(FileName); - if (MF->ModuleName.empty()) { - getDiagnostics().Report(Loc, diag::err_module_file_not_module) + if (RMN.Failed) + return false; + + // 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; - return ModuleLoadResult(); + return false; } - auto *Module = PP->getHeaderSearchInfo().lookupModule(MF->ModuleName, false); - return ModuleLoadResult(Module, false); + + return true; } ModuleLoadResult @@ -1349,8 +1359,12 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, return ModuleLoadResult(); } + auto Override = ModuleFileOverrides.find(ModuleName); + bool Explicit = Override != ModuleFileOverrides.end(); + std::string ModuleFileName = - PP->getHeaderSearchInfo().getModuleFileName(Module); + Explicit ? Override->second + : PP->getHeaderSearchInfo().getModuleFileName(Module); // If we don't already have an ASTReader, create one now. if (!ModuleManager) @@ -1366,15 +1380,24 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, Listener->attachToASTReader(*ModuleManager); // Try to load the module file. - unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing; + unsigned ARRFlags = + Explicit ? 0 : ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing; switch (ModuleManager->ReadAST(ModuleFileName, - serialization::MK_ImplicitModule, ImportLoc, - ARRFlags)) { + Explicit ? serialization::MK_ExplicitModule + : serialization::MK_ImplicitModule, + ImportLoc, ARRFlags)) { case ASTReader::Success: break; case ASTReader::OutOfDate: case ASTReader::Missing: { + if (Explicit) { + // ReadAST has already complained for us. + ModuleLoader::HadFatalFailure = true; + KnownModules[Path[0].first] = nullptr; + return ModuleLoadResult(); + } + // The module file is missing or out-of-date. Build it. assert(Module && "missing module file"); // Check whether there is a cycle in the module graph. diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 1c9384218a..c81c81aba4 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -383,16 +383,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, "doesn't support modules"); } - // If we were asked to load any module files, do so now. Don't make any names - // from those modules visible. - for (const auto &ModuleFile : CI.getFrontendOpts().ModuleFiles) { - // FIXME: Use a better source location here. Perhaps inject something - // into the predefines buffer to represent these module files. - if (!CI.loadModuleFile(ModuleFile, - CI.getSourceManager().getLocForStartOfFile( - CI.getSourceManager().getMainFileID()))) + // If we were asked to load any module files, do so now. + for (const auto &ModuleFile : CI.getFrontendOpts().ModuleFiles) + if (!CI.loadModuleFile(ModuleFile)) goto failure; - } // If there is a layout overrides file, attach an external AST source that // provides the layouts from that file. diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 29fa263bda..7e4e20c70a 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -4188,6 +4188,7 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, bool NeedsInputFiles = Listener.needsInputFileVisitation(); bool NeedsSystemInputFiles = Listener.needsSystemInputFileVisitation(); + bool NeedsImports = Listener.needsImportVisitation(); BitstreamCursor InputFilesCursor; if (NeedsInputFiles) { InputFilesCursor = Stream; @@ -4306,6 +4307,24 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, break; } + case IMPORTS: { + if (!NeedsImports) + break; + + unsigned Idx = 0, N = Record.size(); + while (Idx < N) { + // Read information about the AST file. + ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; + Idx += 4; // ImportLoc, Size, ModTime, Signature + unsigned Length = Record[Idx++]; + SmallString<128> ImportedFile(Record.begin() + Idx, + Record.begin() + Idx + Length); + Idx += Length; + Listener.visitImport(ImportedFile); + } + break; + } + default: // No other validation to perform. break; diff --git a/test/Modules/explicit-build.cpp b/test/Modules/explicit-build.cpp index 0911837ed8..05bbe71781 100644 --- a/test/Modules/explicit-build.cpp +++ b/test/Modules/explicit-build.cpp @@ -2,16 +2,16 @@ // ------------------------------- // Build chained modules A, B, and C -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-name=a -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/a.pcm \ // RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty // -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-file=%t/a.pcm \ // RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/b.pcm \ // RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty // -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-file=%t/b.pcm \ // RUN: -fmodule-name=c -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/c.pcm \ // RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty @@ -20,7 +20,7 @@ // ------------------------------- // Build B with an implicit build of A -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/b-not-a.pcm \ // RUN: 2>&1 | FileCheck --check-prefix=CHECK-B-NO-A %s // @@ -29,123 +29,127 @@ // ------------------------------- // Check that we can use the explicitly-built A, B, and C modules. -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -I%S/Inputs/explicit-build \ // RUN: -fmodule-file=%t/a.pcm \ // RUN: -verify %s -DHAVE_A // -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ -// RUN: -fmodule-file=%t/a.pcm \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -I%S/Inputs/explicit-build \ // RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \ +// RUN: -fmodule-file=%t/a.pcm \ // RUN: -verify %s -DHAVE_A // -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -I%S/Inputs/explicit-build \ // RUN: -fmodule-file=%t/b.pcm \ // RUN: -verify %s -DHAVE_A -DHAVE_B // -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -I%S/Inputs/explicit-build \ // RUN: -fmodule-file=%t/a.pcm \ // RUN: -fmodule-file=%t/b.pcm \ // RUN: -verify %s -DHAVE_A -DHAVE_B // -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -I%S/Inputs/explicit-build \ // RUN: -fmodule-file=%t/a.pcm \ // RUN: -fmodule-file=%t/b.pcm \ // RUN: -fmodule-file=%t/c.pcm \ // RUN: -verify %s -DHAVE_A -DHAVE_B -DHAVE_C // -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -I%S/Inputs/explicit-build \ // RUN: -fmodule-file=%t/a.pcm \ -// RUN: -fmodule-file=%t/b.pcm \ // RUN: -fmodule-file=%t/c.pcm \ -// RUN: -verify %s -INCLUDE_ALL -DHAVE_A -DHAVE_B -DHAVE_C +// RUN: -verify %s -DHAVE_A -DHAVE_B -DHAVE_C -#ifdef INCLUDE_ALL +#if HAVE_A #include "a.h" - #include "b.h" - #include "c.h" static_assert(a == 1, ""); +#else + const int use_a = a; // expected-error {{undeclared identifier}} +#endif + +#if HAVE_B + #include "b.h" static_assert(b == 2, ""); - static_assert(c == 3, ""); #else - const int use_a = a; - #ifndef HAVE_A - // expected-error@-2 {{undeclared identifier}} - #else - // expected-error@-4 {{must be imported from module 'a'}} - // expected-note@Inputs/explicit-build/a.h:* {{here}} - #endif + const int use_b = b; // expected-error {{undeclared identifier}} +#endif - const int use_b = b; - #ifndef HAVE_B - // expected-error@-2 {{undeclared identifier}} - #else - // expected-error@-4 {{must be imported from module 'b'}} - // expected-note@Inputs/explicit-build/b.h:* {{here}} - #endif +#if HAVE_C + #include "c.h" + static_assert(c == 3, ""); +#else + const int use_c = c; // expected-error {{undeclared identifier}} +#endif - const int use_c = c; - #ifndef HAVE_C - // expected-error@-2 {{undeclared identifier}} - #else - // expected-error@-4 {{must be imported from module 'c'}} - // expected-note@Inputs/explicit-build/c.h:* {{here}} - #endif +#if HAVE_A && HAVE_B && HAVE_C +// expected-no-diagnostics #endif // ------------------------------- // Check that we can use a mixture of implicit and explicit modules. -// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -I%S/Inputs/explicit-build \ // RUN: -fmodule-file=%t/b-not-a.pcm \ -// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \ -// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AND-B-NO-A %s +// RUN: -verify %s -DHAVE_A -DHAVE_B // ------------------------------- -// Check that mixing an implicit and explicit form of the 'a' module is rejected. -// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// Try to use two different flavors of the 'a' module. +// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-file=%t/a.pcm \ // RUN: -fmodule-file=%t/b-not-a.pcm \ -// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AND-B-NO-A %s +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s // -// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-file=%t/a.pcm \ // RUN: -fmodule-file=%t/b-not-a.pcm \ // RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \ -// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AND-B-NO-A %s +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s // -// FIXME: We should load module map files specified on the command line and -// module map files in include paths on demand to allow this, and possibly -// also the previous case. -// CHECK-A-AND-B-NO-A: fatal error: module 'a' {{.*}} is not defined in any loaded module map - -// ------------------------------- -// Try to use two different flavors of the 'a' module. -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-name=a -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/a-alt.pcm \ // RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty // -// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-file=%t/a.pcm \ // RUN: -fmodule-file=%t/a-alt.pcm \ // RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \ // RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s // -// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-file=%t/a-alt.pcm \ // RUN: -fmodule-file=%t/a.pcm \ // RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \ // RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s // -// CHECK-MULTIPLE-AS: error: module 'a' has already been loaded; cannot load module file '{{.*a(-alt)?}}.pcm' +// CHECK-MULTIPLE-AS: error: module 'a' is defined in both '{{.*}}/a{{.*}}.pcm' and '{{.*}}/a{{.*}}.pcm' // ------------------------------- // Try to import a PCH with -fmodule-file= -// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-name=a -emit-pch %S/Inputs/explicit-build/a.h -o %t/a.pch \ // RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty // -// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ // RUN: -fmodule-file=%t/a.pch \ // RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AS-PCH %s // // CHECK-A-AS-PCH: fatal error: AST file '{{.*}}a.pch' was not built as a module + +// ------------------------------- +// Try to import a non-AST file with -fmodule-file= +// +// RUN: touch %t/not.pcm +// +// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/not.pcm \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-BAD-FILE %s +// +// RUN: not %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/nonexistent.pcm \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-BAD-FILE %s +// +// CHECK-BAD-FILE: fatal error: file '{{.*}}t.pcm' is not a precompiled module file