diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 13e2865a52bf..f4ab4800c9e7 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -197,7 +197,11 @@ def err_conflicting_module_names : Error< 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; + "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; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 07812bdc8391..2dac20bcb0ff 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1279,6 +1279,7 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { struct ReadModuleNames : ASTReaderListener { CompilerInstance &CI; std::vector ModuleFileStack; + std::vector ModuleNameStack; bool Failed; bool TopFileIsModule; @@ -1295,20 +1296,29 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { } ModuleFileStack.push_back(FileName); + ModuleNameStack.push_back(StringRef()); if (ASTReader::readASTFileControlBlock(FileName, CI.getFileManager(), *this)) { - CI.getDiagnostics().Report(SourceLocation(), - diag::err_module_file_not_found) + CI.getDiagnostics().Report( + SourceLocation(), CI.getFileManager().getBufferForFile(FileName) + ? diag::err_module_file_invalid + : diag::err_module_file_not_found) << FileName; - // FIXME: Produce a note stack explaining how we got here. + 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 { if (ModuleFileStack.size() == 1) TopFileIsModule = true; + ModuleNameStack.back() = ModuleName; auto &ModuleFile = CI.ModuleFileOverrides[ModuleName]; if (!ModuleFile.empty() && diff --git a/clang/test/Modules/explicit-build.cpp b/clang/test/Modules/explicit-build.cpp index ce3a1af41626..ff98f92b1f55 100644 --- a/clang/test/Modules/explicit-build.cpp +++ b/clang/test/Modules/explicit-build.cpp @@ -148,11 +148,24 @@ // RUN: -fmodule-file=%t/not.pcm \ // RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-BAD-FILE %s // +// CHECK-BAD-FILE: fatal error: file '{{.*}}not.pcm' is not a valid precompiled module file + // 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 +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-NO-FILE %s // -// CHECK-BAD-FILE: fatal error: file '{{.*}}t.pcm' is not a precompiled module file +// CHECK-NO-FILE: fatal error: module file '{{.*}}nonexistent.pcm' not found + +// RUN: mv %t/a.pcm %t/a-tmp.pcm +// RUN: not %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/c.pcm \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-NO-FILE-INDIRECT %s +// RUN: mv %t/a-tmp.pcm %t/a.pcm +// +// 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 that we don't get upset if B's timestamp is newer than C's.