diff --git a/base/REPL.jl b/base/REPL.jl index 9c787c7b92469..d52b34683a03c 100644 --- a/base/REPL.jl +++ b/base/REPL.jl @@ -48,8 +48,8 @@ end function eval_user_input(ast::ANY, backend::REPLBackend) iserr, lasterr, bt = false, (), nothing + Base.enable_catch_fatal() while true - Base.set_fatal_eh() try if iserr put!(backend.response_channel, (lasterr, bt)) diff --git a/base/error.jl b/base/error.jl index 0ed7716f8f429..cd8c5b2c092b3 100644 --- a/base/error.jl +++ b/base/error.jl @@ -50,16 +50,20 @@ macro assert(ex, msgs...) :($(esc(ex)) ? $(nothing) : throw(Main.Base.AssertionError($msg))) end +## fatal errors ## isfatal(error) = false -if isdefined(Main, :Base) isfatal(::StackOverflowError) = true isfatal(::OutOfMemoryError) = true isfatal(::UndefVarError) = true -end -set_fatal_eh() = ccall(:jl_set_fatal_eh, Void, ()) -rethrow_fatal() = ccall(:jl_rethrow_fatal, Void, ()) +enable_catch_fatal() = ccall(:jl_enable_catch_fatal, Void, ()) +disable_catch_fatal() = ccall(:jl_disable_catch_fatal, Void, ()) +if isdefined(Main, :Base) +rethrow_if_fatal(error) = isfatal(error) && ccall(:jl_rethrow_fatal, Void, ()) +else +rethrow_if_fatal(error) = nothing +end """ diff --git a/base/test.jl b/base/test.jl index a7dba03d76ac0..1be406f6c4421 100644 --- a/base/test.jl +++ b/base/test.jl @@ -231,9 +231,14 @@ macro test_throws(extype, ex) orig_ex = Expr(:quote,ex) result = quote try - Returned($(esc(ex))) - catch _e - Threw(_e, nothing) + Base.enable_catch_fatal() + try + Returned($(esc(ex))) + catch _e + Threw(_e, nothing) + end + finally + Base.disable_catch_fatal() end end Base.remove_linenums!(result) diff --git a/src/builtins.c b/src/builtins.c index 7187595fb55a2..e238c5416f9b6 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -197,6 +197,7 @@ JL_DLLEXPORT void jl_enter_handler(jl_handler_t *eh) JL_SIGATOMIC_BEGIN(); eh->prev = jl_current_task->eh; eh->gcstack = jl_pgcstack; + eh->catch_fatal = 0; #ifdef JULIA_ENABLE_THREADING eh->gc_state = jl_gc_state(); eh->locks_len = jl_current_task->locks.len; diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index ce620adbd423a..96e2b64ef458b 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -3078,9 +3078,8 @@ f(x) = yt(x) ;; (enter L) - push handler with catch block at label L ;; (leave n) - pop N exception handlers ((trycatch) - (let ((catch (make-label)) - (notfatal (make-label)) - (endl (make-label))) + (let ((catch (make-label)) + (endl (make-label))) (emit `(enter ,catch)) (set! handler-level (+ handler-level 1)) (let* ((v1 (compile (cadr e) @@ -3096,9 +3095,7 @@ f(x) = yt(x) (set! handler-level (- handler-level 1)) (mark-label catch) (emit `(leave 1)) - (emit `(gotoifnot ,`(call (top isfatal) ,'(the_exception)) ,notfatal)) - (emit `(call (top rethrow_fatal))) - (mark-label notfatal) + (emit `(call (top rethrow_if_fatal) ,'(the_exception))) (let ((v2 (compile (caddr e) break-labels value tail))) (if val (emit `(= ,val ,v2))) (if endl (mark-label endl)) diff --git a/src/julia.h b/src/julia.h index d1a48bce1a25e..7edd2575b94cf 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1380,6 +1380,7 @@ typedef struct _jl_handler_t { jl_gcframe_t *gcstack; struct _jl_handler_t *prev; int8_t gc_state; + int8_t catch_fatal; #ifdef JULIA_ENABLE_THREADING size_t locks_len; #endif @@ -1404,8 +1405,6 @@ typedef struct _jl_task_t { // current exception handler jl_handler_t *eh; - // fatal exception handler - jl_handler_t *fatal_eh; // saved gc stack top for context switches jl_gcframe_t *gcstack; // current module, or NULL if this task has not set one @@ -1436,7 +1435,8 @@ JL_DLLEXPORT jl_value_t *jl_switchto(jl_task_t *t, jl_value_t *arg); JL_DLLEXPORT void JL_NORETURN jl_throw(jl_value_t *e); JL_DLLEXPORT void JL_NORETURN jl_rethrow(void); JL_DLLEXPORT void JL_NORETURN jl_rethrow_other(jl_value_t *e); -JL_DLLEXPORT void jl_set_fatal_eh(void); +JL_DLLEXPORT void jl_enable_catch_fatal(void); +JL_DLLEXPORT void jl_disable_catch_fatal(void); JL_DLLEXPORT void jl_rethrow_fatal(void); #ifdef JULIA_ENABLE_THREADING diff --git a/src/task.c b/src/task.c index 2dad3931ae77e..5fa0297d17381 100644 --- a/src/task.c +++ b/src/task.c @@ -526,21 +526,31 @@ JL_DLLEXPORT void jl_rethrow(void) throw_internal(jl_exception_in_transit); } -JL_DLLEXPORT void jl_set_fatal_eh(void) +JL_DLLEXPORT void jl_rethrow_other(jl_value_t *e) { - jl_current_task->fatal_eh = jl_current_task->eh; + throw_internal(e); } -JL_DLLEXPORT void jl_rethrow_fatal(void) +JL_DLLEXPORT void jl_enable_catch_fatal(void) { - if (jl_current_task->eh != jl_current_task->fatal_eh) { - jl_rethrow(); - } + assert(jl_current_task->eh); + jl_current_task->eh->catch_fatal = 1; } -JL_DLLEXPORT void jl_rethrow_other(jl_value_t *e) +JL_DLLEXPORT void jl_disable_catch_fatal(void) { - throw_internal(e); + assert(jl_current_task->eh); + jl_current_task->eh->catch_fatal = 0; +} + +JL_DLLEXPORT void jl_rethrow_fatal(void) +{ + if (jl_current_task + && jl_current_task->eh + && jl_current_task->eh->catch_fatal) { + return; + } + jl_rethrow(); } JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, size_t ssize) @@ -566,7 +576,6 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, size_t ssize) t->backtrace = jl_nothing; // there is no active exception handler available on this stack yet t->eh = NULL; - t->fatal_eh = NULL; t->gcstack = NULL; t->stkbuf = NULL; t->tid = 0; @@ -674,7 +683,6 @@ void jl_init_root_task(void *stack, size_t ssize) jl_current_task->exception = jl_nothing; jl_current_task->backtrace = jl_nothing; jl_current_task->eh = NULL; - jl_current_task->fatal_eh = NULL; jl_current_task->gcstack = NULL; jl_current_task->tid = ti_tid; #ifdef JULIA_ENABLE_THREADING diff --git a/test/core.jl b/test/core.jl index 69058b2bf42a2..01a06668aaa30 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1103,12 +1103,14 @@ type I2619{T} end bad2619 = false function i2619() + Base.enable_catch_fatal() global e2619 = try I2619{Float64}(0.0f) global bad2619 = true catch _e _e end + Base.disable_catch_fatal() end i2619() @test !bad2619 @@ -2274,11 +2276,13 @@ OLD_STDOUT = STDOUT file = open(tempname(), "w") redirect_stdout(file) versioninfo() +Base.enable_catch_fatal() try type Foo{T} val::Bar{T} end end +Base.disable_catch_fatal() gc() redirect_stdout(OLD_STDOUT) close(file) diff --git a/test/replutil.jl b/test/replutil.jl index d87ba11ad2b1c..141bfa72b8ec4 100644 --- a/test/replutil.jl +++ b/test/replutil.jl @@ -74,10 +74,12 @@ macro except_str(expr, err_type) return quote let local err + Base.enable_catch_fatal() try $(esc(expr)) catch err end + Base.disable_catch_fatal() @test typeof(err) === $(esc(err_type)) buff = IOBuffer() showerror(buff, err) diff --git a/test/simdloop.jl b/test/simdloop.jl index 771383aedf419..012d14ebe47f5 100644 --- a/test/simdloop.jl +++ b/test/simdloop.jl @@ -61,13 +61,7 @@ let j=4 # Index that is local to loop @simd for simd_loop_local=1:0 end - simd_loop_local_present = true - try - simd_loop_local += 1 - catch - simd_loop_local_present = false - end - @test !simd_loop_local_present + @test_throws UndefVarError simd_loop_local += 1 end import Base.SimdLoop.SimdError diff --git a/test/stacktraces.jl b/test/stacktraces.jl index c0ba1faaa3c18..aeb0e26eddde8 100644 --- a/test/stacktraces.jl +++ b/test/stacktraces.jl @@ -54,7 +54,7 @@ let ct = current_task() yieldto(@task yieldto(ct)) @test catch_backtrace() == StackFrame[] - @noinline bad_function() = throw(UndefVarError(:nonexistent)) + @noinline bad_function() = error("error") @noinline function try_stacktrace() try bad_function()