diff --git a/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp b/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp index afee5dbf93aa0..e27bd3e218017 100644 --- a/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp +++ b/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp @@ -425,6 +425,13 @@ Error IncludeTreeActionController::finalizeModuleBuild( ModuleScanInstance.getInvocation().getLangOpts(), ModuleScanInstance.getInvocation().getCodeGenOpts()); auto Builder = BuilderStack.pop_back_val(); + + // If there was an error, bail out early. The state of `Builder` may be + // inconsistent since there is no guarantee that exitedInclude or + // finalizeModuleBuild have been called for all imports. + if (ModuleScanInstance.getDiagnostics().hasUnrecoverableErrorOccurred()) + return Error::success(); // Already reported. + auto Tree = Builder->finishIncludeTree(ModuleScanInstance, ModuleScanInstance.getInvocation()); if (!Tree) diff --git a/clang/test/ClangScanDeps/modules-include-tree-missing-header.c b/clang/test/ClangScanDeps/modules-include-tree-missing-header.c new file mode 100644 index 0000000000000..d8636f82de42d --- /dev/null +++ b/clang/test/ClangScanDeps/modules-include-tree-missing-header.c @@ -0,0 +1,28 @@ +// Tests that a missing header in a module that is itself imported by another +// module does not crash/assert in the IncludeTreeBuilder. + +// RUN: rm -rf %t +// RUN: split-file %s %t + +// RUN: not clang-scan-deps -format experimental-include-tree-full -cas-path %t/cas -- %clang -fmodules -fmodules-cache-path=%t/cache -c %t/tu0.m -I%t +// RUN: not clang-scan-deps -format experimental-include-tree-full -cas-path %t/cas -- %clang -fmodules -fmodules-cache-path=%t/cache -c %t/tu1.m -I%t + +//--- module.modulemap +module MissingH { + header "missing.h" +} + +module Importer { + header "importer.h" +} + +//--- not-missing.h + +//--- importer.h +@import MissingH; + +//--- tu0.m +@import MissingH; + +//--- tu1.m +@import Importer;