[clang][deps] Stop lexing if hit a failure while loading a PCH/module in a submodule. by vsapsai · Pull Request #146976 · llvm/llvm-project (original) (raw)
@llvm/pr-subscribers-clang
Author: Volodymyr Sapsai (vsapsai)
Changes
Otherwise we are continuing in an invalid state and can easily crash.
It is a follow-up to cde90e6 but an important difference is when a failure happens in a submodule. In this case in Preprocessor::HandleEndOfFile tok::eof is replaced by tok::annot_module_end. And after exiting a file with bad #include/#import we work with a new buffer, so BufferPtr < BufferEnd. As there are no signs to stop lexing we just keep doing it.
The fix is the same as in dc9fdaf in Lexer::LexTokenInternal but this time in Lexer::LexDependencyDirectiveToken as well.
rdar://152499276
Full diff: https://github.com/llvm/llvm-project/pull/146976.diff
2 Files Affected:
- (modified) clang/lib/Lex/Lexer.cpp (+3)
- (added) clang/test/ClangScanDeps/fatal-module-loader-error.m (+42)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 30ac48b8010b8..8a0560615bf97 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -4589,6 +4589,9 @@ bool Lexer::LexDependencyDirectiveToken(Token &Result) {
if (Result.is(tok::hash) && Result.isAtStartOfLine()) { PP->HandleDirective(Result);
- if (PP->hadModuleLoaderFatalFailure())
// With a fatal failure in the module loader, we abort parsing.
return false; } if (Result.is(tok::raw_identifier)) { diff --git a/clang/test/ClangScanDeps/fatal-module-loader-error.m b/clang/test/ClangScanDeps/fatal-module-loader-error.m new file mode 100644 index 0000000000000..ed4d8628a6471 --- /dev/null +++ b/clang/test/ClangScanDeps/fatal-module-loader-error.m @@ -0,0 +1,42 @@ +// This tests that after a fatal module loader error, we do not continue parsing.return true;- +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: mkdir %t/ModulesCache +// RUN: touch %t/ModulesCache/Unusable.pcm
- +// RUN: not clang-scan-deps -format experimental-full -mode preprocess-dependency-directives --
+// RUN: %clang -fmodules -fimplicit-modules -Xclang -fdisable-module-hash -fmodules-cache-path=%t/ModulesCache
+// RUN: -F %t/Frameworks -c %t/test.m -o %t/test.o +// RUN: ls %t/ModulesCache | not grep AfterUnusable - +//--- Frameworks/Unusable.framework/Headers/Unusable.h +// empty +//--- Frameworks/Unusable.framework/Modules/module.modulemap +framework module Unusable { header "Unusable.h" }
- +//--- Frameworks/AfterUnusable.framework/Headers/AfterUnusable.h +// empty +//--- Frameworks/AfterUnusable.framework/Modules/module.modulemap +framework module AfterUnusable { header "AfterUnusable.h" }
- +//--- Frameworks/Importer.framework/Headers/Importer.h +#import <Importer/ImportUnusable.h>
+// Parsing should have stopped and we should not handle AfterUnusable. +#import <AfterUnusable/AfterUnusable.h> + +//--- Frameworks/Importer.framework/Headers/ImportUnusable.h +// It is important that this header is a submodule. +#import <Unusable/Unusable.h> +// Parsing should have stopped and we should not handle AfterUnusable. +#import <AfterUnusable/AfterUnusable.h> + +//--- Frameworks/Importer.framework/Modules/module.modulemap +framework module Importer {
- umbrella header "Importer.h"
- module * { export * }
- export * +}
- +//--- test.m +#import <Importer/Importer.h>