diff --git a/libinterp/corefcn/cellfun.cc b/libinterp/corefcn/cellfun.cc --- a/libinterp/corefcn/cellfun.cc +++ b/libinterp/corefcn/cellfun.cc @@ -70,17 +70,22 @@ get_output_list (octave_idx_type count, octave_value& error_handler) { octave_value_list tmp; + + bool execution_error = false; + try { tmp = func.do_multi_index_op (nargout, inputlist); } - catch (octave_execution_exception) + catch (const octave_execution_exception&) { if (error_handler.is_defined ()) - error_state = 1; + execution_error = true; + else + octave_throw_execution_exception (); } - if (error_state) + if (execution_error) { if (error_handler.is_defined ()) { @@ -96,14 +101,7 @@ get_output_list (octave_idx_type count, buffer_error_messages--; - error_state = 0; - tmp = error_handler.do_multi_index_op (nargout, errlist); - - buffer_error_messages++; - - if (error_state) - tmp.clear (); } else tmp.clear (); diff --git a/libinterp/corefcn/error.cc b/libinterp/corefcn/error.cc --- a/libinterp/corefcn/error.cc +++ b/libinterp/corefcn/error.cc @@ -93,22 +93,11 @@ static octave_map Vlast_error_stack; // // Valid values: // -// -2: an error has occurred, but don't print any messages. -// -1: an error has occurred, we are printing a traceback // 0: no error // 1: an error has occurred // int error_state = 0; -// Current warning state. -// -// Valid values: -// -// 0: no warning -// 1: a warning has occurred -// -int warning_state = 0; - // Tell the error handler whether to print messages, or just store // them for later. Used for handling errors in eval() and // the 'unwind_protect' statement. @@ -123,8 +112,6 @@ bool discard_warning_messages = false; void reset_error_handler (void) { - error_state = 0; - warning_state = 0; buffer_error_messages = 0; discard_error_messages = false; } @@ -146,6 +133,26 @@ initialize_last_error_stack (void) return octave_call_stack::empty_backtrace (); } +static void +debug_or_throw_exception (void) +{ + if ((interactive || forced_interactive) + && Vdebug_on_error && octave_call_stack::caller_user_code ()) + { + unwind_protect frame; + frame.protect_var (Vdebug_on_error); + Vdebug_on_error = false; + + tree_evaluator::debug_mode = true; + + tree_evaluator::current_frame = octave_call_stack::current_frame (); + + do_keyboard (octave_value_list ()); + } + else + octave_throw_execution_exception (); +} + // Warning messages are never buffered. static void @@ -204,7 +211,7 @@ verror (bool save_last_error, std::ostre std::string base_msg = output_buf.str (); - bool to_beep_or_not_to_beep_p = Vbeep_on_error && ! error_state; + bool to_beep_or_not_to_beep_p = Vbeep_on_error; std::string msg_string; @@ -238,7 +245,7 @@ verror (bool save_last_error, std::ostre msg_string += base_msg + "\n"; - if (! error_state && save_last_error) + if (save_last_error) { // This is the first error in a possible series. @@ -328,48 +335,6 @@ pr_where (const char *who) } } -// Note that we don't actually print any message if the error string -// is just "" or "\n". This allows error ("") and error ("\n") to -// just set the error state. - -static void -error_1 (std::ostream& os, const char *name, const char *id, - const char *fmt, va_list args, bool with_cfn = false) -{ - if (error_state != -2) - { - if (fmt && *fmt) - { - size_t len = strlen (fmt); - - if (len > 0) - { - if (fmt[len - 1] == '\n') - { - if (len > 1) - { - // Strip newline before issuing error - std::string tmp_fmt (fmt, len - 1); - verror (true, os, name, id, tmp_fmt.c_str (), - args, with_cfn); - } - - error_state = -2; - } - else - { - verror (true, os, name, id, fmt, args, with_cfn); - - if (! error_state) - error_state = 1; - } - } - } - else - panic ("error_1: invalid format"); - } -} - void vmessage (const char *name, const char *fmt, va_list args) { @@ -405,7 +370,8 @@ void usage_1 (const char *id, const char *fmt, va_list args) { verror (true, std::cerr, "usage", id, fmt, args); - error_state = -1; + + debug_or_throw_exception (); } void @@ -439,37 +405,49 @@ usage_with_id (const char *id, const cha } static void -error_2 (const char *id, const char *fmt, va_list args, bool with_cfn = false) +error_1 (std::ostream& os, const char *name, const char *id, + const char *fmt, va_list args, bool with_cfn = false) { - int init_state = error_state; + if (fmt) + { + if (*fmt) + { + size_t len = strlen (fmt); - error_1 (std::cerr, "error", id, fmt, args, with_cfn); + if (len > 0) + { + if (fmt[len - 1] == '\n') + { + if (len > 1) + { + char *tmp_fmt = strsave (fmt); + tmp_fmt[len - 1] = '\0'; + verror (true, os, name, id, tmp_fmt, args, with_cfn); + delete [] tmp_fmt; + } + } + else + { + verror (true, os, name, id, fmt, args, with_cfn); - bool in_user_code = octave_call_stack::caller_user_code () != 0; + bool in_user_code = octave_call_stack::caller_user_code () != 0; - if (error_state != -2 && in_user_code && ! discard_error_messages) - pr_where ("error"); + if (in_user_code && ! discard_error_messages) + pr_where ("error"); + } + } + } + } + else + panic ("error_1: invalid format"); - if (interactive && Vdebug_on_error && init_state == 0 && in_user_code) - { - unwind_protect frame; - frame.protect_var (Vdebug_on_error); - Vdebug_on_error = false; - - error_state = 0; - - tree_evaluator::debug_mode = true; - - tree_evaluator::current_frame = octave_call_stack::current_frame (); - - do_keyboard (octave_value_list ()); - } + debug_or_throw_exception (); } void verror (const char *fmt, va_list args) { - error_2 ("", fmt, args); + error_1 (std::cerr, "error", "", fmt, args); } void @@ -484,7 +462,7 @@ error (const char *fmt, ...) void verror_with_cfn (const char *fmt, va_list args) { - error_2 ("", fmt, args, true); + error_1 (std::cerr, "error", "", fmt, args, true); } void @@ -499,7 +477,7 @@ error_with_cfn (const char *fmt, ...) void verror_with_id (const char *id, const char *fmt, va_list args) { - error_2 (id, fmt, args); + error_1 (std::cerr, "error", id, fmt, args); } void @@ -514,7 +492,7 @@ error_with_id (const char *id, const cha void verror_with_id_cfn (const char *id, const char *fmt, va_list args) { - error_2 (id, fmt, args, true); + error_1 (std::cerr, "error", id, fmt, args, true); } void @@ -628,7 +606,7 @@ warning_1 (const char *id, const char *f { // Handle this warning as an error. - error_2 (id, fmt, args); + error_1 (std::cerr, "error", id, fmt, args); } else if (warn_opt == 1) { @@ -647,14 +625,11 @@ warning_1 (const char *id, const char *f bool in_user_code = octave_call_stack::caller_user_code () != 0; - if (! fmt_suppresses_backtrace && in_user_code - && Vbacktrace_on_warning && ! warning_state + && Vbacktrace_on_warning && ! discard_warning_messages) pr_where ("warning"); - warning_state = 1; - if ((interactive || forced_interactive) && Vdebug_on_warning && in_user_code) { @@ -856,120 +831,117 @@ error. Typically @var{err} is returned { const octave_scalar_map err = args(0).scalar_map_value (); - if (! error_state) + if (err.contains ("message") && err.contains ("identifier")) { - if (err.contains ("message") && err.contains ("identifier")) + std::string msg = err.contents ("message").string_value (); + std::string id = err.contents ("identifier").string_value (); + int len = msg.length (); + + std::string file; + std::string nm; + int l = -1; + int c = -1; + + octave_map err_stack = initialize_last_error_stack (); + + if (err.contains ("stack")) { - std::string msg = err.contents ("message").string_value (); - std::string id = err.contents ("identifier").string_value (); - int len = msg.length (); + err_stack = err.contents ("stack").map_value (); - std::string file; - std::string nm; - int l = -1; - int c = -1; + if (err_stack.numel () > 0) + { + if (err_stack.contains ("file")) + file = err_stack.contents ("file")(0).string_value (); - octave_map err_stack = initialize_last_error_stack (); + if (err_stack.contains ("name")) + nm = err_stack.contents ("name")(0).string_value (); - if (err.contains ("stack")) + if (err_stack.contains ("line")) + l = err_stack.contents ("line")(0).nint_value (); + + if (err_stack.contains ("column")) + c = err_stack.contents ("column")(0).nint_value (); + } + } + + // Ugh. + char *tmp_msg = strsave (msg.c_str ()); + if (tmp_msg[len-1] == '\n') + { + if (len > 1) { - err_stack = err.contents ("stack").map_value (); + tmp_msg[len - 1] = '\0'; + rethrow_error (id.c_str (), "%s\n", tmp_msg); + } + } + else + rethrow_error (id.c_str (), "%s", tmp_msg); + delete [] tmp_msg; - if (err_stack.numel () > 0) + // FIXME: is this the right thing to do for Vlast_error_stack? + // Should it be saved and restored with unwind_protect? + + Vlast_error_stack = err_stack; + + if (err.contains ("stack")) + { + if (file.empty ()) + { + if (nm.empty ()) { - if (err_stack.contains ("file")) - file = err_stack.contents ("file")(0).string_value (); - - if (err_stack.contains ("name")) - nm = err_stack.contents ("name")(0).string_value (); - - if (err_stack.contains ("line")) - l = err_stack.contents ("line")(0).nint_value (); - - if (err_stack.contains ("column")) - c = err_stack.contents ("column")(0).nint_value (); - } - } - - // Ugh. - char *tmp_msg = strsave (msg.c_str ()); - if (tmp_msg[len-1] == '\n') - { - if (len > 1) - { - tmp_msg[len - 1] = '\0'; - rethrow_error (id.c_str (), "%s\n", tmp_msg); - } - } - else - rethrow_error (id.c_str (), "%s", tmp_msg); - delete [] tmp_msg; - - // FIXME: is this the right thing to do for Vlast_error_stack? - // Should it be saved and restored with unwind_protect? - - Vlast_error_stack = err_stack; - - if (err.contains ("stack")) - { - if (file.empty ()) - { - if (nm.empty ()) + if (l > 0) { - if (l > 0) - { - if (c > 0) - pr_where_1 ("error: near line %d, column %d", - l, c); - else - pr_where_1 ("error: near line %d", l); - } - } - else - { - if (l > 0) - { - if (c > 0) - pr_where_1 ("error: called from '%s' near line %d, column %d", - nm.c_str (), l, c); - else - pr_where_1 ("error: called from '%d' near line %d", - nm.c_str (), l); - } + if (c > 0) + pr_where_1 ("error: near line %d, column %d", + l, c); + else + pr_where_1 ("error: near line %d", l); } } else { - if (nm.empty ()) + if (l > 0) { - if (l > 0) - { - if (c > 0) - pr_where_1 ("error: in file %s near line %d, column %d", - file.c_str (), l, c); - else - pr_where_1 ("error: in file %s near line %d", - file.c_str (), l); - } + if (c > 0) + pr_where_1 ("error: called from '%s' near line %d, column %d", + nm.c_str (), l, c); + else + pr_where_1 ("error: called from '%d' near line %d", + nm.c_str (), l); } - else + } + } + else + { + if (nm.empty ()) + { + if (l > 0) { - if (l > 0) - { - if (c > 0) - pr_where_1 ("error: called from '%s' in file %s near line %d, column %d", - nm.c_str (), file.c_str (), l, c); - else - pr_where_1 ("error: called from '%d' in file %s near line %d", - nm.c_str (), file.c_str (), l); - } + if (c > 0) + pr_where_1 ("error: in file %s near line %d, column %d", + file.c_str (), l, c); + else + pr_where_1 ("error: in file %s near line %d", + file.c_str (), l); + } + } + else + { + if (l > 0) + { + if (c > 0) + pr_where_1 ("error: called from '%s' in file %s near line %d, column %d", + nm.c_str (), file.c_str (), l, c); + else + pr_where_1 ("error: called from '%d' in file %s near line %d", + nm.c_str (), file.c_str (), l); } } } } - else - error ("rethrow: ERR structure must contain the fields 'message and 'identifier'"); } + else + error ("rethrow: ERR structure must contain the fields 'message and 'identifier'"); } return retval; } @@ -994,31 +966,28 @@ maybe_extract_message_id (const std::str { std::string arg1 = args(0).string_value (); - if (! error_state) + // For compatibility with Matlab, an identifier must contain + // ':', but not at the beginning or the end, and it must not + // contain '%' (even if it is not a valid conversion + // operator) or whitespace. + + if (arg1.find_first_of ("% \f\n\r\t\v") == std::string::npos + && arg1.find (':') != std::string::npos + && arg1[0] != ':' + && arg1[arg1.length ()-1] != ':') { - // For compatibility with Matlab, an identifier must contain - // ':', but not at the beginning or the end, and it must not - // contain '%' (even if it is not a valid conversion - // operator) or whitespace. + if (nargin > 1) + { + id = arg1; - if (arg1.find_first_of ("% \f\n\r\t\v") == std::string::npos - && arg1.find (':') != std::string::npos - && arg1[0] != ':' - && arg1[arg1.length ()-1] != ':') - { - if (nargin > 1) - { - id = arg1; + nargs.resize (nargin-1); - nargs.resize (nargin-1); - - for (int i = 1; i < nargin; i++) - nargs(i-1) = args(i); - } - else - nargs(0) = "call to " + caller - + " with message identifier requires message"; + for (int i = 1; i < nargin; i++) + nargs(i-1) = args(i); } + else + nargs(0) = "call to " + caller + + " with message identifier requires message"; } } @@ -1163,12 +1132,7 @@ disable escape sequence expansion use a // handle_message, error_with_id, etc. } else - { - have_fmt = maybe_extract_message_id ("error", args, nargs, id); - - if (error_state) - return retval; - } + have_fmt = maybe_extract_message_id ("error", args, nargs, id); handle_message (error_with_id, id.c_str (), "unspecified error", nargs, have_fmt); @@ -1192,6 +1156,8 @@ warning_query (const std::string& id_arg octave_idx_type nel = ident.numel (); + assert (nel != 0); + bool found = false; std::string val; @@ -1219,13 +1185,14 @@ warning_query (const std::string& id_arg } } - if (found) - { - retval.assign ("identifier", id); - retval.assign ("state", val); - } - else - error ("warning: unable to find default warning state!"); + // The warning state "all" is always supposed to remain in the list, + // so we should always find a state, either explicitly or by using the + // state for "all". + + assert (found); + + retval.assign ("identifier", id); + retval.assign ("state", val); return retval; } @@ -1810,11 +1777,6 @@ fields are set to their default values.\ octave_value retval; int nargin = args.length (); - unwind_protect frame; - - frame.protect_var (error_state); - error_state = 0; - if (nargin < 2) { octave_scalar_map err; @@ -1849,47 +1811,47 @@ fields are set to their default values.\ int new_error_line = -1; int new_error_column = -1; - if (! error_state && new_err.contains ("message")) + if (new_err.contains ("message")) { const std::string tmp = new_err.getfield ("message").string_value (); new_error_message = tmp; } - if (! error_state && new_err.contains ("identifier")) + if (new_err.contains ("identifier")) { const std::string tmp = new_err.getfield ("identifier").string_value (); new_error_id = tmp; } - if (! error_state && new_err.contains ("stack")) + if (new_err.contains ("stack")) { new_err_stack = new_err.getfield ("stack").scalar_map_value (); - if (! error_state && new_err_stack.contains ("file")) + if (new_err_stack.contains ("file")) { const std::string tmp = new_err_stack.getfield ("file").string_value (); new_error_file = tmp; } - if (! error_state && new_err_stack.contains ("name")) + if (new_err_stack.contains ("name")) { const std::string tmp = new_err_stack.getfield ("name").string_value (); new_error_name = tmp; } - if (! error_state && new_err_stack.contains ("line")) + if (new_err_stack.contains ("line")) { const int tmp = new_err_stack.getfield ("line").nint_value (); new_error_line = tmp; } - if (! error_state && new_err_stack.contains ("column")) + if (new_err_stack.contains ("column")) { const int tmp = new_err_stack.getfield ("column").nint_value (); @@ -1897,35 +1859,31 @@ fields are set to their default values.\ } } - if (! error_state) + Vlast_error_message = new_error_message; + Vlast_error_id = new_error_id; + + if (new_err.contains ("stack")) { - Vlast_error_message = new_error_message; - Vlast_error_id = new_error_id; + new_err_stack.setfield ("file", new_error_file); + new_err_stack.setfield ("name", new_error_name); + new_err_stack.setfield ("line", new_error_line); + new_err_stack.setfield ("column", new_error_column); + Vlast_error_stack = new_err_stack; + } + else + { + // No stack field. Fill it in with backtrace info. + octave_idx_type curr_frame = -1; - if (new_err.contains ("stack")) - { - new_err_stack.setfield ("file", new_error_file); - new_err_stack.setfield ("name", new_error_name); - new_err_stack.setfield ("line", new_error_line); - new_err_stack.setfield ("column", new_error_column); - Vlast_error_stack = new_err_stack; - } - else - { - // No stack field. Fill it in with backtrace info. - octave_idx_type curr_frame = -1; - - Vlast_error_stack - = octave_call_stack::backtrace (0, curr_frame); - } + Vlast_error_stack + = octave_call_stack::backtrace (0, curr_frame); } } else error ("lasterror: argument must be a structure or a string"); } - if (! error_state) - retval = err; + retval = err; } else print_usage (); @@ -1951,36 +1909,26 @@ With two arguments, also set the last me { octave_value_list retval; - unwind_protect frame; - - frame.protect_var (error_state); - error_state = 0; - int argc = args.length () + 1; if (argc < 4) { string_vector argv = args.make_argv ("lasterr"); - if (! error_state) + std::string prev_error_id = Vlast_error_id; + std::string prev_error_message = Vlast_error_message; + + if (argc > 2) + Vlast_error_id = argv(2); + + if (argc > 1) + Vlast_error_message = argv(1); + + if (argc == 1 || nargout > 0) { - std::string prev_error_id = Vlast_error_id; - std::string prev_error_message = Vlast_error_message; - - if (argc > 2) - Vlast_error_id = argv(2); - - if (argc > 1) - Vlast_error_message = argv(1); - - if (argc == 1 || nargout > 0) - { - retval(1) = prev_error_id; - retval(0) = prev_error_message; - } + retval(1) = prev_error_id; + retval(0) = prev_error_message; } - else - error ("lasterr: all arguments must be strings"); } else print_usage (); @@ -2012,26 +1960,20 @@ With two arguments, also set the last me { string_vector argv = args.make_argv ("lastwarn"); - if (! error_state) + std::string prev_warning_id = Vlast_warning_id; + std::string prev_warning_message = Vlast_warning_message; + + if (argc > 2) + Vlast_warning_id = argv(2); + + if (argc > 1) + Vlast_warning_message = argv(1); + + if (argc == 1 || nargout > 0) { - std::string prev_warning_id = Vlast_warning_id; - std::string prev_warning_message = Vlast_warning_message; - - if (argc > 2) - Vlast_warning_id = argv(2); - - if (argc > 1) - Vlast_warning_message = argv(1); - - if (argc == 1 || nargout > 0) - { - warning_state = 0; - retval(1) = prev_warning_id; - retval(0) = prev_warning_message; - } + retval(1) = prev_warning_id; + retval(0) = prev_warning_message; } - else - error ("lastwarn: all arguments must be strings"); } else print_usage (); @@ -2160,7 +2102,6 @@ last_warning_id (void) void interpreter_try (unwind_protect& frame) { - frame.protect_var (error_state); frame.protect_var (buffer_error_messages); frame.protect_var (Vdebug_on_error); frame.protect_var (Vdebug_on_warning); diff --git a/libinterp/corefcn/gripes.cc b/libinterp/corefcn/gripes.cc --- a/libinterp/corefcn/gripes.cc +++ b/libinterp/corefcn/gripes.cc @@ -205,15 +205,6 @@ gripe_logical_conversion (void) } void -gripe_library_execution_error (void) -{ - octave_exception_state = octave_no_exception; - - if (! error_state) - error ("caught execution error in library function"); -} - -void gripe_invalid_inquiry_subscript (void) { error ("invalid dimension inquiry of a non-existent value"); diff --git a/libinterp/corefcn/gripes.h b/libinterp/corefcn/gripes.h --- a/libinterp/corefcn/gripes.h +++ b/libinterp/corefcn/gripes.h @@ -114,9 +114,6 @@ extern OCTINTERP_API void gripe_logical_conversion (void); extern OCTINTERP_API void -gripe_library_execution_error (void); - -extern OCTINTERP_API void gripe_invalid_inquiry_subscript (void); extern OCTINTERP_API void diff --git a/libinterp/corefcn/jit-typeinfo.cc b/libinterp/corefcn/jit-typeinfo.cc --- a/libinterp/corefcn/jit-typeinfo.cc +++ b/libinterp/corefcn/jit-typeinfo.cc @@ -215,41 +215,20 @@ octave_jit_cast_any_complex (Complex c) extern "C" void octave_jit_gripe_nan_to_logical_conversion (void) { - try - { - gripe_nan_to_logical_conversion (); - } - catch (const octave_execution_exception&) - { - gripe_library_execution_error (); - } + gripe_nan_to_logical_conversion (); } extern "C" void octave_jit_ginvalid_index (void) { - try - { - gripe_invalid_index (); - } - catch (const octave_execution_exception&) - { - gripe_library_execution_error (); - } + gripe_invalid_index (); } extern "C" void octave_jit_gindex_range (int nd, int dim, octave_idx_type iext, octave_idx_type ext) { - try - { - gripe_index_out_of_range (nd, dim, iext, ext); - } - catch (const octave_execution_exception&) - { - gripe_library_execution_error (); - } + gripe_index_out_of_range (nd, dim, iext, ext); } extern "C" jit_matrix @@ -281,19 +260,12 @@ octave_jit_paren_scalar (jit_matrix *mat octave_idx_type idx_count) { // FIXME: Replace this with a more optimal version - try - { - Array idx; - make_indices (indicies, idx_count, idx); + Array idx; + make_indices (indicies, idx_count, idx); - Array ret = mat->array->index (idx); - return ret.xelem (0); - } - catch (const octave_execution_exception&) - { - gripe_library_execution_error (); - return 0; - } + Array ret = mat->array->index (idx); + + return ret.xelem (0); } extern "C" jit_matrix @@ -302,20 +274,14 @@ octave_jit_paren_scalar_subsasgn (jit_ma { // FIXME: Replace this with a more optimal version jit_matrix ret; - try - { - Array idx; - make_indices (indices, idx_count, idx); - Matrix temp (1, 1); - temp.xelem(0) = value; - mat->array->assign (idx, temp); - ret.update (mat->array); - } - catch (const octave_execution_exception&) - { - gripe_library_execution_error (); - } + Array idx; + make_indices (indices, idx_count, idx); + + Matrix temp (1, 1); + temp.xelem(0) = value; + mat->array->assign (idx, temp); + ret.update (mat->array); return ret; } diff --git a/libinterp/corefcn/load-path.cc b/libinterp/corefcn/load-path.cc --- a/libinterp/corefcn/load-path.cc +++ b/libinterp/corefcn/load-path.cc @@ -91,12 +91,10 @@ load_path::dir_info::update (void) initialize (); } } - catch (octave_execution_exception) + catch (const octave_execution_exception&) { // Skip updating if we don't know where we are, but // don't treat it as an error. - - error_state = 0; } } else if (fs.mtime () + fs.time_resolution () > dir_time_last_checked) @@ -159,7 +157,7 @@ load_path::dir_info::initialize (void) abs_dir_cache[abs_name] = *this; } - catch (octave_execution_exception) + catch (const octave_execution_exception&) { // Skip updating if we don't know where we are. } diff --git a/libinterp/corefcn/ls-mat-ascii.cc b/libinterp/corefcn/ls-mat-ascii.cc --- a/libinterp/corefcn/ls-mat-ascii.cc +++ b/libinterp/corefcn/ls-mat-ascii.cc @@ -369,15 +369,18 @@ save_mat_ascii_data (std::ostream& os, c if (val.is_complex_type ()) warning ("save: omitting imaginary part for ASCII file"); - Matrix m = val.matrix_value (true); + Matrix m; - if (error_state) + try + { + m = val.matrix_value (true); + } + catch (const octave_execution_exception&) { success = false; + } - error_state = 0; - } - else + if (success) { long old_precision = os.precision (); diff --git a/libinterp/corefcn/mex.cc b/libinterp/corefcn/mex.cc --- a/libinterp/corefcn/mex.cc +++ b/libinterp/corefcn/mex.cc @@ -3104,9 +3104,20 @@ mexCallMATLAB (int nargout, mxArray *arg for (int i = 0; i < nargin; i++) args(i) = mxArray::as_octave_value (argin[i]); - octave_value_list retval = feval (fname, args, nargout); - - if (error_state && mex_context->trap_feval_error == 0) + bool execution_error = false; + + octave_value_list retval; + + try + { + retval = feval (fname, args, nargout); + } + catch (const octave_execution_exception&) + { + execution_error = true; + } + + if (execution_error && mex_context->trap_feval_error == 0) { // FIXME: is this the correct way to clean up? abort() is // going to trigger a long jump, so the normal class destructors @@ -3137,13 +3148,7 @@ mexCallMATLAB (int nargout, mxArray *arg while (num_to_copy < nargout) argout[num_to_copy++] = 0; - if (error_state) - { - error_state = 0; - return 1; - } - else - return 0; + return execution_error ? 1 : 0; } void @@ -3162,14 +3167,19 @@ mexEvalString (const char *s) octave_value_list ret; - ret = eval_string (s, false, parse_status, 0); - - if (parse_status || error_state) + bool execution_error = false; + + try { - error_state = 0; - - retval = 1; + ret = eval_string (s, false, parse_status, 0); } + catch (const octave_execution_exception&) + { + execution_error = true; + } + + if (parse_status || execution_error) + retval = 1; return retval; } diff --git a/libinterp/corefcn/rand.cc b/libinterp/corefcn/rand.cc --- a/libinterp/corefcn/rand.cc +++ b/libinterp/corefcn/rand.cc @@ -1181,7 +1181,7 @@ using std::unordered_map; { idx = Array (dim_vector (1, idx_len)); } - catch (std::bad_alloc) + catch (const std::bad_alloc&) { // Looks like n is too big and short_shuffle is false. // Let's try again, but this time with the alternative. diff --git a/libinterp/corefcn/svd.cc b/libinterp/corefcn/svd.cc --- a/libinterp/corefcn/svd.cc +++ b/libinterp/corefcn/svd.cc @@ -129,10 +129,7 @@ decomposition, eliminating the unnecessa int nargin = args.length (); if (nargin < 1 || nargin > 2 || nargout == 2 || nargout > 3) - { - print_usage (); - return retval; - } + print_usage (); octave_value arg = args(0); @@ -140,10 +137,7 @@ decomposition, eliminating the unnecessa octave_idx_type nc = arg.columns (); if (arg.ndims () != 2) - { - error ("svd: A must be a 2-D matrix"); - return retval; - } + error ("svd: A must be a 2-D matrix"); bool isfloat = arg.is_single_type (); @@ -164,12 +158,14 @@ decomposition, eliminating the unnecessa retval(1) = FloatMatrix (nr, nc); retval(0) = FloatDiagMatrix (nr, nr, 1.0f); break; + case SVD::economy: retval(2) = FloatDiagMatrix (0, nc, 1.0f); retval(1) = FloatMatrix (0, 0); retval(0) = FloatDiagMatrix (nr, 0, 1.0f); break; - case SVD::sigma_only: default: + + case SVD::sigma_only: default: retval(0) = FloatMatrix (0, 1); break; } @@ -183,12 +179,14 @@ decomposition, eliminating the unnecessa retval(1) = Matrix (nr, nc); retval(0) = DiagMatrix (nr, nr, 1.0); break; + case SVD::economy: retval(2) = DiagMatrix (0, nc, 1.0); retval(1) = Matrix (0, 0); retval(0) = DiagMatrix (nr, 0, 1.0); break; - case SVD::sigma_only: default: + + case SVD::sigma_only: default: retval(0) = Matrix (0, 1); break; } @@ -202,56 +200,40 @@ decomposition, eliminating the unnecessa { FloatMatrix tmp = arg.float_matrix_value (); - if (! error_state) + if (tmp.any_element_is_inf_or_nan ()) + error ("svd: cannot take SVD of matrix containing Inf or NaN values"); + + FloatSVD result (tmp, type, driver); + + FloatDiagMatrix sigma = result.singular_values (); + + if (nargout == 0 || nargout == 1) + retval(0) = sigma.extract_diag (); + else { - if (tmp.any_element_is_inf_or_nan ()) - { - error ("svd: cannot take SVD of matrix containing Inf or NaN values"); - return retval; - } - - FloatSVD result (tmp, type, driver); - - FloatDiagMatrix sigma = result.singular_values (); - - if (nargout == 0 || nargout == 1) - { - retval(0) = sigma.extract_diag (); - } - else - { - retval(2) = result.right_singular_matrix (); - retval(1) = sigma; - retval(0) = result.left_singular_matrix (); - } + retval(2) = result.right_singular_matrix (); + retval(1) = sigma; + retval(0) = result.left_singular_matrix (); } } else if (arg.is_complex_type ()) { FloatComplexMatrix ctmp = arg.float_complex_matrix_value (); - if (! error_state) + if (ctmp.any_element_is_inf_or_nan ()) + error ("svd: cannot take SVD of matrix containing Inf or NaN values"); + + FloatComplexSVD result (ctmp, type, driver); + + FloatDiagMatrix sigma = result.singular_values (); + + if (nargout == 0 || nargout == 1) + retval(0) = sigma.extract_diag (); + else { - if (ctmp.any_element_is_inf_or_nan ()) - { - error ("svd: cannot take SVD of matrix containing Inf or NaN values"); - return retval; - } - - FloatComplexSVD result (ctmp, type, driver); - - FloatDiagMatrix sigma = result.singular_values (); - - if (nargout == 0 || nargout == 1) - { - retval(0) = sigma.extract_diag (); - } - else - { - retval(2) = result.right_singular_matrix (); - retval(1) = sigma; - retval(0) = result.left_singular_matrix (); - } + retval(2) = result.right_singular_matrix (); + retval(1) = sigma; + retval(0) = result.left_singular_matrix (); } } } @@ -261,63 +243,44 @@ decomposition, eliminating the unnecessa { Matrix tmp = arg.matrix_value (); - if (! error_state) + if (tmp.any_element_is_inf_or_nan ()) + error ("svd: cannot take SVD of matrix containing Inf or NaN values"); + + SVD result (tmp, type, driver); + + DiagMatrix sigma = result.singular_values (); + + if (nargout == 0 || nargout == 1) + retval(0) = sigma.extract_diag (); + else { - if (tmp.any_element_is_inf_or_nan ()) - { - error ("svd: cannot take SVD of matrix containing Inf or NaN values"); - return retval; - } - - SVD result (tmp, type, driver); - - DiagMatrix sigma = result.singular_values (); - - if (nargout == 0 || nargout == 1) - { - retval(0) = sigma.extract_diag (); - } - else - { - retval(2) = result.right_singular_matrix (); - retval(1) = sigma; - retval(0) = result.left_singular_matrix (); - } + retval(2) = result.right_singular_matrix (); + retval(1) = sigma; + retval(0) = result.left_singular_matrix (); } } else if (arg.is_complex_type ()) { ComplexMatrix ctmp = arg.complex_matrix_value (); - if (! error_state) + if (ctmp.any_element_is_inf_or_nan ()) + error ("svd: cannot take SVD of matrix containing Inf or NaN values"); + + ComplexSVD result (ctmp, type, driver); + + DiagMatrix sigma = result.singular_values (); + + if (nargout == 0 || nargout == 1) + retval(0) = sigma.extract_diag (); + else { - if (ctmp.any_element_is_inf_or_nan ()) - { - error ("svd: cannot take SVD of matrix containing Inf or NaN values"); - return retval; - } - - ComplexSVD result (ctmp, type, driver); - - DiagMatrix sigma = result.singular_values (); - - if (nargout == 0 || nargout == 1) - { - retval(0) = sigma.extract_diag (); - } - else - { - retval(2) = result.right_singular_matrix (); - retval(1) = sigma; - retval(0) = result.left_singular_matrix (); - } + retval(2) = result.right_singular_matrix (); + retval(1) = sigma; + retval(0) = result.left_singular_matrix (); } } else - { - gripe_wrong_type_arg ("svd", arg); - return retval; - } + gripe_wrong_type_arg ("svd", arg); } } diff --git a/libinterp/corefcn/toplev.cc b/libinterp/corefcn/toplev.cc --- a/libinterp/corefcn/toplev.cc +++ b/libinterp/corefcn/toplev.cc @@ -636,20 +636,18 @@ main_loop (void) break; } } - catch (octave_interrupt_exception) + catch (const octave_interrupt_exception&) { recover_from_exception (); octave_stdout << "\n"; if (quitting_gracefully) return exit_status; } - catch (octave_execution_exception) + catch (const octave_execution_exception&) { recover_from_exception (); - std::cerr << "error: unhandled execution exception -- trying to return to prompt" - << std::endl; } - catch (std::bad_alloc) + catch (const std::bad_alloc&) { recover_from_exception (); std::cerr << "error: out of memory -- trying to return to prompt" diff --git a/libinterp/corefcn/toplev.h b/libinterp/corefcn/toplev.h --- a/libinterp/corefcn/toplev.h +++ b/libinterp/corefcn/toplev.h @@ -515,12 +515,9 @@ private: \ F ARGS; \ } \ - OCTAVE_IGNORE_EXCEPTION (octave_interrupt_exception) \ - OCTAVE_IGNORE_EXCEPTION (octave_execution_exception) \ - OCTAVE_IGNORE_EXCEPTION (std::bad_alloc) \ - \ - if (error_state) \ - error_state = 0; \ + OCTAVE_IGNORE_EXCEPTION (const octave_interrupt_exception&) \ + OCTAVE_IGNORE_EXCEPTION (const octave_execution_exception&) \ + OCTAVE_IGNORE_EXCEPTION (const std::bad_alloc&) \ } \ while (0) diff --git a/libinterp/corefcn/utils.cc b/libinterp/corefcn/utils.cc --- a/libinterp/corefcn/utils.cc +++ b/libinterp/corefcn/utils.cc @@ -1473,7 +1473,7 @@ character @nospell{\"@xbackslashchar{}0\ else retval = false; } - catch (octave_execution_exception) + catch (const octave_execution_exception&) { retval = false; } diff --git a/libinterp/corefcn/variables.cc b/libinterp/corefcn/variables.cc --- a/libinterp/corefcn/variables.cc +++ b/libinterp/corefcn/variables.cc @@ -268,7 +268,6 @@ generate_struct_completions (const std:: unwind_protect frame; frame.protect_var (error_state); - frame.protect_var (warning_state); frame.protect_var (discard_error_messages); frame.protect_var (discard_warning_messages); @@ -377,9 +376,14 @@ safe_symbol_lookup (const std::string& s unwind_protect frame; interpreter_try (frame); - retval = symbol_table::find (symbol_name); - - error_state = 0; + try + { + retval = symbol_table::find (symbol_name); + } + catch (const octave_execution_exception&) + { + // Ignore errors. + } return retval; } diff --git a/libinterp/dldfcn/__magick_read__.cc b/libinterp/dldfcn/__magick_read__.cc --- a/libinterp/dldfcn/__magick_read__.cc +++ b/libinterp/dldfcn/__magick_read__.cc @@ -691,7 +691,6 @@ read_file (const std::string& filename, catch (Magick::Exception& e) { error ("Magick++ exception: %s", e.what ()); - error_state = 1; } } @@ -1382,7 +1381,6 @@ write_file (const std::string& filename, catch (Magick::Exception& e) { error ("Magick++ exception: %s", e.what ()); - error_state = 1; } } diff --git a/libinterp/octave-value/ov-builtin.cc b/libinterp/octave-value/ov-builtin.cc --- a/libinterp/octave-value/ov-builtin.cc +++ b/libinterp/octave-value/ov-builtin.cc @@ -124,29 +124,22 @@ octave_builtin::do_multi_index_op (int n curr_lvalue_list = lvalue_list; } - try - { - BEGIN_PROFILER_BLOCK (octave_builtin) + BEGIN_PROFILER_BLOCK (octave_builtin) - retval = (*f) (args, nargout); - // Do not allow null values to be returned from functions. - // FIXME: perhaps true builtins should be allowed? - retval.make_storable_values (); - // Fix the case of a single undefined value. - // This happens when a compiled function uses - // octave_value retval; - // instead of - // octave_value_list retval; - // the idiom is very common, so we solve that here. - if (retval.length () == 1 && retval.xelem (0).is_undefined ()) - retval.clear (); + retval = (*f) (args, nargout); + // Do not allow null values to be returned from functions. + // FIXME: perhaps true builtins should be allowed? + retval.make_storable_values (); + // Fix the case of a single undefined value. + // This happens when a compiled function uses + // octave_value retval; + // instead of + // octave_value_list retval; + // the idiom is very common, so we solve that here. + if (retval.length () == 1 && retval.xelem (0).is_undefined ()) + retval.clear (); - END_PROFILER_BLOCK - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } + END_PROFILER_BLOCK } return retval; diff --git a/libinterp/octave-value/ov-class.cc b/libinterp/octave-value/ov-class.cc --- a/libinterp/octave-value/ov-class.cc +++ b/libinterp/octave-value/ov-class.cc @@ -1172,13 +1172,21 @@ octave_class::reconstruct_exemplar (void interpreter_try (frame); - octave_value_list result - = ctor.do_multi_index_op (1, octave_value_list ()); + bool execution_error = false; - if (! error_state && result.length () == 1) + octave_value_list result; + + try + { + result = ctor.do_multi_index_op (1, octave_value_list ()); + } + catch (const octave_execution_exception&) + { + execution_error = true; + } + + if (! execution_error && result.length () == 1) retval = true; - - error_state = false; } else warning ("no constructor for class %s", c_name.c_str ()); diff --git a/libinterp/octave-value/ov-fcn-handle.cc b/libinterp/octave-value/ov-fcn-handle.cc --- a/libinterp/octave-value/ov-fcn-handle.cc +++ b/libinterp/octave-value/ov-fcn-handle.cc @@ -2066,8 +2066,18 @@ octave_fcn_binder::maybe_binder (const o unwind_protect frame; interpreter_try (frame); - root_val = make_fcn_handle (head_name); - if (error_state) + bool execution_error = false; + + try + { + root_val = make_fcn_handle (head_name); + } + catch (const octave_execution_exception&) + { + execution_error = true; + } + + if (execution_error) bad = true; } } diff --git a/libinterp/octave-value/ov-mex-fcn.cc b/libinterp/octave-value/ov-mex-fcn.cc --- a/libinterp/octave-value/ov-mex-fcn.cc +++ b/libinterp/octave-value/ov-mex-fcn.cc @@ -145,18 +145,11 @@ octave_mex_function::do_multi_index_op ( frame.add_fcn (octave_call_stack::pop); - try - { - BEGIN_PROFILER_BLOCK (octave_mex_function) + BEGIN_PROFILER_BLOCK (octave_mex_function) - retval = call_mex (have_fmex, mex_fcn_ptr, args, nargout, this); + retval = call_mex (have_fmex, mex_fcn_ptr, args, nargout, this); - END_PROFILER_BLOCK - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } + END_PROFILER_BLOCK } return retval; diff --git a/libinterp/octave-value/ov-oncleanup.cc b/libinterp/octave-value/ov-oncleanup.cc --- a/libinterp/octave-value/ov-oncleanup.cc +++ b/libinterp/octave-value/ov-oncleanup.cc @@ -78,29 +78,26 @@ octave_oncleanup::~octave_oncleanup (voi frame.protect_var (quit_allowed); quit_allowed = false; - // Clear errors. - frame.protect_var (error_state); - error_state = 0; - try { // Run the actual code. fcn.do_multi_index_op (0, octave_value_list ()); } - catch (octave_interrupt_exception) + catch (const octave_interrupt_exception&) { // Swallow the interrupt. warning ("onCleanup: interrupt occured in cleanup action"); } + catch (const octave_execution_exception&) + { + // Propagate the error. + throw; + } catch (...) // Yes, the black hole. We're in a d-tor. { // This shouldn't happen, in theory. error ("onCleanup: internal error: unhandled exception in cleanup action"); } - - // FIXME: can this happen now? - if (error_state) - frame.discard_first (); } octave_scalar_map diff --git a/libinterp/octave-value/ov.cc b/libinterp/octave-value/ov.cc --- a/libinterp/octave-value/ov.cc +++ b/libinterp/octave-value/ov.cc @@ -1490,16 +1490,9 @@ octave_value::assign (assign_op op, cons if (f) { - try - { - f (*rep, octave_value_list (), *rhs.rep); - // Usually unnecessary, but may be needed (complex arrays). - maybe_mutate (); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } + f (*rep, octave_value_list (), *rhs.rep); + // Usually unnecessary, but may be needed (complex arrays). + maybe_mutate (); } else { @@ -1993,14 +1986,7 @@ do_binary_op (octave_value::binary_op op if (f) { - try - { - retval = f (v1, v2); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } + retval = f (v1, v2); } else gripe_binary_op (octave_value::binary_op_as_string (op), @@ -2015,16 +2001,7 @@ do_binary_op (octave_value::binary_op op = octave_value_typeinfo::lookup_binary_op (op, t1, t2); if (f) - { - try - { - retval = f (*v1.rep, *v2.rep); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } - } + retval = f (*v1.rep, *v2.rep); else { octave_value tv1; @@ -2143,16 +2120,7 @@ do_binary_op (octave_value::binary_op op f = octave_value_typeinfo::lookup_binary_op (op, t1, t2); if (f) - { - try - { - retval = f (*tv1.rep, *tv2.rep); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } - } + retval = f (*tv1.rep, *tv2.rep); else gripe_binary_op (octave_value::binary_op_as_string (op), v1.type_name (), v2.type_name ()); @@ -2251,16 +2219,7 @@ do_binary_op (octave_value::compound_bin = octave_value_typeinfo::lookup_binary_class_op (op); if (f) - { - try - { - retval = f (v1, v2); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } - } + retval = f (v1, v2); else retval = decompose_binary_op (op, v1, v2); } @@ -2270,16 +2229,7 @@ do_binary_op (octave_value::compound_bin = octave_value_typeinfo::lookup_binary_op (op, t1, t2); if (f) - { - try - { - retval = f (*v1.rep, *v2.rep); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } - } + retval = f (*v1.rep, *v2.rep); else retval = decompose_binary_op (op, v1, v2); } @@ -2316,16 +2266,7 @@ do_cat_op (const octave_value& v1, const = octave_value_typeinfo::lookup_cat_op (t1, t2); if (f) - { - try - { - retval = f (*v1.rep, *v2.rep, ra_idx); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } - } + retval = f (*v1.rep, *v2.rep, ra_idx); else { octave_value tv1; @@ -2521,16 +2462,7 @@ do_unary_op (octave_value::unary_op op, = octave_value_typeinfo::lookup_unary_class_op (op); if (f) - { - try - { - retval = f (v); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } - } + retval = f (v); else gripe_unary_op (octave_value::unary_op_as_string (op), v.class_name ()); @@ -2544,16 +2476,7 @@ do_unary_op (octave_value::unary_op op, = octave_value_typeinfo::lookup_unary_op (op, t); if (f) - { - try - { - retval = f (*v.rep); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } - } + retval = f (*v.rep); else { octave_value tv; @@ -2615,14 +2538,7 @@ octave_value::do_non_const_unary_op (una { make_unique (); - try - { - f (*rep); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } + f (*rep); } else { @@ -2643,14 +2559,7 @@ octave_value::do_non_const_unary_op (una if (f) { - try - { - f (*rep); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } + f (*rep); if (old_rep && --old_rep->count == 0) delete old_rep; @@ -2690,16 +2599,7 @@ octave_value::do_non_const_unary_op (una f = octave_value_typeinfo::lookup_non_const_unary_op (op, t); if (f) - { - try - { - f (*rep); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } - } + f (*rep); else *this = do_unary_op (op, *this); } diff --git a/libinterp/octave.cc b/libinterp/octave.cc --- a/libinterp/octave.cc +++ b/libinterp/octave.cc @@ -279,14 +279,14 @@ safe_source_file (const std::string& fil { source_file (file_name, context, verbose, require_file, warn_for); } - catch (octave_interrupt_exception) + catch (const octave_interrupt_exception&) { recover_from_exception (); octave_stdout << "\n"; if (quitting_gracefully) clean_up_and_exit (exit_status); } - catch (octave_execution_exception) + catch (const octave_execution_exception&) { recover_from_exception (); gripe_safe_source_exception (file_name, "unhandled execution exception"); @@ -394,14 +394,14 @@ execute_eval_option_code (const std::str { eval_string (code, false, parse_status, 0); } - catch (octave_interrupt_exception) + catch (const octave_interrupt_exception&) { recover_from_exception (); octave_stdout << "\n"; if (quitting_gracefully) clean_up_and_exit (exit_status); } - catch (octave_execution_exception) + catch (const octave_execution_exception&) { recover_from_exception (); std::cerr << "error: unhandled execution exception -- eval failed" diff --git a/libinterp/parse-tree/oct-parse.in.yy b/libinterp/parse-tree/oct-parse.in.yy --- a/libinterp/parse-tree/oct-parse.in.yy +++ b/libinterp/parse-tree/oct-parse.in.yy @@ -2247,7 +2247,6 @@ octave_base_parser::finish_colon_express unwind_protect frame; frame.protect_var (error_state); - frame.protect_var (warning_state); frame.protect_var (discard_error_messages); frame.protect_var (discard_warning_messages); @@ -2268,7 +2267,7 @@ octave_base_parser::finish_colon_express { octave_value tmp = e->rvalue1 (); - if (! (error_state || warning_state)) + if (! error_state) { tree_constant *tc_retval = new tree_constant (tmp, base->line (), base->column ()); @@ -3800,7 +3799,6 @@ octave_base_parser::finish_array_list (t unwind_protect frame; frame.protect_var (error_state); - frame.protect_var (warning_state); frame.protect_var (discard_error_messages); frame.protect_var (discard_warning_messages); @@ -3812,7 +3810,7 @@ octave_base_parser::finish_array_list (t { octave_value tmp = array_list->rvalue1 (); - if (! (error_state || warning_state)) + if (! error_state) { tree_constant *tc_retval = new tree_constant (tmp, array_list->line (), @@ -4999,13 +4997,21 @@ the security considerations that the eva int parse_status = 0; - octave_value_list tmp = eval_string (args(0), nargout > 0, - parse_status, nargout); - - if (nargin > 1 && (parse_status != 0 || error_state)) + bool execution_error = false; + + octave_value_list tmp; + + try { - error_state = 0; - + tmp = eval_string (args(0), nargout > 0, parse_status, nargout); + } + catch (const octave_execution_exception&) + { + execution_error = true; + } + + if (nargin > 1 && (parse_status != 0 || execution_error)) + { // Set up for letting the user print any messages from // errors that occurred in the first part of this eval(). @@ -5016,8 +5022,16 @@ the security considerations that the eva if (nargout > 0) retval = tmp; } - else if (nargout > 0) - retval = tmp; + else + { + if (nargout > 0) + retval = tmp; + + // FIXME: we should really be rethrowing whatever exception occurred, + // not just throwing an execution exception. + if (execution_error) + octave_throw_execution_exception (); + } } else print_usage (); @@ -5156,16 +5170,22 @@ Like @code{eval}, except that the expres int parse_status = 0; - octave_value_list tmp = eval_string (args(1), nargout > 0, - parse_status, nargout); - - if (nargout > 0) - retval = tmp; - - if (nargin > 2 && (parse_status != 0 || error_state)) + bool execution_error = false; + + octave_value_list tmp; + + try { - error_state = 0; - + tmp = eval_string (args(1), nargout > 0, + parse_status, nargout); + } + catch (const octave_execution_exception&) + { + execution_error = true; + } + + if (nargin > 2 && (parse_status != 0 || execution_error)) + { // Set up for letting the user print any messages from // errors that occurred in the first part of this eval(). @@ -5176,6 +5196,17 @@ Like @code{eval}, except that the expres retval = (nargout > 0) ? tmp : octave_value_list (); } + else + { + if (nargout > 0) + retval = tmp; + + // FIXME: we should really be rethrowing whatever + // exception occurred, not just throwing an + // execution exception. + if (execution_error) + octave_throw_execution_exception (); + } } } else diff --git a/libinterp/parse-tree/pt-eval.cc b/libinterp/parse-tree/pt-eval.cc --- a/libinterp/parse-tree/pt-eval.cc +++ b/libinterp/parse-tree/pt-eval.cc @@ -59,6 +59,8 @@ bool tree_evaluator::debug_mode = false; bool tree_evaluator::quiet_breakpoint_flag = false; +bool tree_evaluator::unwind_protect_exception = false; + tree_evaluator::stmt_list_type tree_evaluator::statement_context = tree_evaluator::other; @@ -751,11 +753,7 @@ tree_evaluator::visit_statement (tree_st // result_values(0) = tmp_result; } } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } - catch (std::bad_alloc) + catch (const std::bad_alloc&) { // FIXME: We want to use error_with_id here so that we set // the error state, give users control over this error @@ -902,15 +900,22 @@ tree_evaluator::visit_try_catch_command tree_statement_list *try_code = cmd.body (); + bool execution_error = false; + if (try_code) { - try_code->accept (*this); + try + { + try_code->accept (*this); + } + catch (const octave_execution_exception&) + { + execution_error = true; + } } - if (error_state) + if (execution_error) { - error_state = 0; - if (catch_code) { // Set up for letting the user print any messages from errors that @@ -923,21 +928,15 @@ tree_evaluator::visit_try_catch_command if (expr_id) { + ult = expr_id->lvalue (); octave_scalar_map err; - ult = expr_id->lvalue (); - - if (error_state) - return; - err.assign ("message", last_error_message ()); err.assign ("identifier", last_error_id ()); err.assign ("stack", last_error_stack ()); - if (! error_state) - ult.assign (octave_value::op_asn_eq, err); - + ult.assign (octave_value::op_asn_eq, err); } if (catch_code) @@ -954,14 +953,6 @@ tree_evaluator::do_unwind_protect_cleanu frame.protect_var (octave_interrupt_state); octave_interrupt_state = 0; - // We want to run the cleanup code without error_state being set, - // but we need to restore its value, so that any errors encountered - // in the first part of the unwind_protect are not completely - // ignored. - - frame.protect_var (error_state); - error_state = 0; - // We want to preserve the last location info for possible // backtracking. frame.add_fcn (octave_call_stack::set_line, @@ -980,8 +971,17 @@ tree_evaluator::do_unwind_protect_cleanu frame.protect_var (tree_break_command::breaking); tree_break_command::breaking = 0; - if (list) - list->accept (*this); + bool execution_error_in_cleanup = false; + + try + { + if (list) + list->accept (*this); + } + catch (const octave_execution_exception&) + { + execution_error_in_cleanup = true; + } // The unwind_protects are popped off the stack in the reverse of // the order they are pushed on. @@ -1011,24 +1011,30 @@ tree_evaluator::do_unwind_protect_cleanu // whatever they were when the cleanup block was entered. if (tree_break_command::breaking || tree_return_command::returning) - { - frame.discard (2); - } + frame.discard (2); else - { - frame.run (2); - } + frame.run (2); - // We don't want to ignore errors that occur in the cleanup code, so - // if an error is encountered there, leave error_state alone. - // Otherwise, set it back to what it was before. + // We don't want to ignore errors that occur in the cleanup code, + // so if an error is encountered there, rethrow the exception. + // Otherwise, rethrow any exception that might have occurred in the + // unwind_protect block. - if (error_state) + if (execution_error_in_cleanup) frame.discard (2); else frame.run (2); frame.run (); + + // FIXME: we should really be rethrowing whatever exception occurred, + // not just throwing an execution exception. + if (unwind_protect_exception || execution_error_in_cleanup) + { + unwind_protect_exception = false; + + octave_throw_execution_exception (); + } } void @@ -1040,15 +1046,20 @@ tree_evaluator::visit_unwind_protect_com if (unwind_protect_code) { + unwind_protect_exception = false; + try { unwind_protect_code->accept (*this); } - catch (...) + catch (const octave_execution_exception&) { + unwind_protect_exception = true; + // Run the cleanup code on exceptions, so that it is run even in case // of interrupt or out-of-memory. do_unwind_protect_cleanup_code (cleanup_code); + // FIXME: should error_state be checked here? // We want to rethrow the exception, even if error_state is set, so // that interrupts continue. diff --git a/libinterp/parse-tree/pt-eval.h b/libinterp/parse-tree/pt-eval.h --- a/libinterp/parse-tree/pt-eval.h +++ b/libinterp/parse-tree/pt-eval.h @@ -153,6 +153,8 @@ public: static bool quiet_breakpoint_flag; + static bool unwind_protect_exception; + // Possible types of evaluation contexts. enum stmt_list_type { diff --git a/liboctave/cruft/misc/quit.h b/liboctave/cruft/misc/quit.h --- a/liboctave/cruft/misc/quit.h +++ b/liboctave/cruft/misc/quit.h @@ -195,18 +195,18 @@ inline void octave_quit (void) #define END_INTERRUPT_WITH_EXCEPTIONS \ } \ - catch (octave_interrupt_exception) \ + catch (const octave_interrupt_exception&) \ { \ octave_interrupt_immediately = saved_octave_interrupt_immediately; \ octave_jump_to_enclosing_context (); \ } \ - catch (octave_execution_exception) \ + catch (const octave_execution_exception&) \ { \ octave_interrupt_immediately = saved_octave_interrupt_immediately; \ octave_exception_state = octave_exec_exception; \ octave_jump_to_enclosing_context (); \ } \ - catch (std::bad_alloc) \ + catch (const std::bad_alloc&) \ { \ octave_interrupt_immediately = saved_octave_interrupt_immediately; \ octave_exception_state = octave_alloc_exception; \ diff --git a/liboctave/util/cmd-edit.cc b/liboctave/util/cmd-edit.cc --- a/liboctave/util/cmd-edit.cc +++ b/liboctave/util/cmd-edit.cc @@ -1668,7 +1668,7 @@ command_editor::do_decode_prompt_string { temp = octave_env::get_current_directory (); } - catch (octave_execution_exception) + catch (const octave_execution_exception&) { temp = ""; } diff --git a/scripts/statistics/base/kurtosis.m b/scripts/statistics/base/kurtosis.m --- a/scripts/statistics/base/kurtosis.m +++ b/scripts/statistics/base/kurtosis.m @@ -158,7 +158,7 @@ endfunction %! kurtosis (1); %! assert (lastwarn (), ""); %! unwind_protect_cleanup -%! warning (wstate, "Octave:divide-by-zero"); +%! warning (wstate); %! end_unwind_protect ## Test input validation diff --git a/scripts/statistics/base/skewness.m b/scripts/statistics/base/skewness.m --- a/scripts/statistics/base/skewness.m +++ b/scripts/statistics/base/skewness.m @@ -159,7 +159,7 @@ endfunction %! skewness (1); %! assert (lastwarn (), ""); %! unwind_protect_cleanup -%! warning (wstate, "Octave:divide-by-zero"); +%! warning (wstate); %! end_unwind_protect ## Test input validation