From efab7d225989e1da9fcded58449339a575a3b08f Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Mon, 28 Sep 2026 23:55:30 +0100 Subject: [PATCH] An error a pass reports fails the compile, even when the pass succeeds A lowering pattern that cannot cast reports "cast from ... is not supported" and carries on, so the pass manager succeeded and runMLIRPasses returned 0: the error was printed and the object file written anyway, and under --emit=jit the program ran and crashed with 0xC0000005. runMLIRPasses now fails when any collected diagnostic is an error. Co-Authored-By: Claude Opus 5.5 --- tslang/test/tester/CMakeLists.txt | 16 ++++++++++++++++ .../tester/lowering-errors/cast_not_supported.ts | 6 ++++++ tslang/tslang/transform.cpp | 8 ++++++++ 3 files changed, 30 insertions(+) create mode 100644 tslang/test/tester/lowering-errors/cast_not_supported.ts diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index 5a695e783..5bfed70f5 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -2339,6 +2339,22 @@ foreach(call_arity_case ${call_arity_cases}) FAIL_REGULAR_EXPRESSION "Stack dump|Assertion failed") endforeach() +# An error reported by a pass that still returns success - a lowering pattern that cannot cast, +# says so and carries on - fails the compile. It used to be printed and then ignored: the object +# file was written, and under --emit=jit the program ran and crashed. Two tests because one +# property cannot say both things: the message is the error we meant, and the exit code is not 0. +set(lowering_error_file "${PROJECT_SOURCE_DIR}/test/tester/lowering-errors/cast_not_supported.ts") +add_test(NAME test-compile-lowering-error-message + COMMAND $ --emit=obj --no-default-lib -mm=none "${lowering_error_file}" + -o "${CMAKE_CURRENT_BINARY_DIR}/lowering-error-message.obj") +set_tests_properties(test-compile-lowering-error-message + PROPERTIES PASS_REGULAR_EXPRESSION "cast from '!ts.array' to '!ts.string' is not supported" + FAIL_REGULAR_EXPRESSION "Stack dump|Assertion failed") +add_test(NAME test-compile-lowering-error-exit + COMMAND $ --emit=obj --no-default-lib -mm=none "${lowering_error_file}" + -o "${CMAKE_CURRENT_BINARY_DIR}/lowering-error-exit.obj") +set_tests_properties(test-compile-lowering-error-exit PROPERTIES WILL_FAIL TRUE) + # @dllname and @linkname are one decorator under two names, and a symbol is bound once: each # case is a program the compiler must reject with the given message instead of binding # something else or making the name unique. diff --git a/tslang/test/tester/lowering-errors/cast_not_supported.ts b/tslang/test/tester/lowering-errors/cast_not_supported.ts new file mode 100644 index 000000000..c3d3bb112 --- /dev/null +++ b/tslang/test/tester/lowering-errors/cast_not_supported.ts @@ -0,0 +1,6 @@ +// Lowering has no cast from an array to a string, and says so with an error. That error has to +// stop the compile: before it did, the program was emitted and run anyway and crashed. +function main() { + let a: number[] | null = [1, 2]; + print("a=" + a); +} diff --git a/tslang/tslang/transform.cpp b/tslang/tslang/transform.cpp index b4df4c4b5..3e605d377 100644 --- a/tslang/tslang/transform.cpp +++ b/tslang/tslang/transform.cpp @@ -200,6 +200,14 @@ int runMLIRPasses(mlir::MLIRContext &context, llvm::SourceMgr &sourceMgr, mlir:: result = 4; } + // A pass can report an error and still succeed - a lowering pattern that cannot cast says so + // and carries on with a value that is not one - so the run's result alone is not the answer. + // Without this the error was printed and the module compiled, linked and run anyway. + if (llvm::any_of(postponedMessages, [](auto &diag) { return diag->getSeverity() == mlir::DiagnosticSeverity::Error; })) + { + result = 4; + } + SourceMgrDiagnosticHandlerEx sourceMgrHandler(sourceMgr, &context); printDiagnostics(sourceMgrHandler, postponedMessages, disableWarnings); return result;