# HG changeset patch # User John W. Eaton # Date 1419228760 18000 # Mon Dec 22 01:12:40 2014 -0500 # Node ID 2a67edb90cef57595edc7383e6812b19084cbd71 # Parent 8b785ca93de7b63ab17cebb8d94e010641b14b24 exception error diffs 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 @@ 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 @@ 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 @@ -92,22 +92,11 @@ // // 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. @@ -122,8 +111,6 @@ void reset_error_handler (void) { - error_state = 0; - warning_state = 0; buffer_error_messages = 0; discard_error_messages = false; } @@ -145,6 +132,26 @@ 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 @@ -170,13 +177,8 @@ std::string msg_string = output_buf.str (); - if (! warning_state) - { - // This is the first warning in a possible series. - - Vlast_warning_id = id; - Vlast_warning_message = msg_string; - } + Vlast_warning_id = id; + Vlast_warning_message = msg_string; if (! Vquiet_warning) { @@ -207,7 +209,7 @@ 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; @@ -241,7 +243,7 @@ msg_string += base_msg + "\n"; - if (! error_state && save_last_error) + if (save_last_error) { // This is the first error in a possible series. @@ -331,51 +333,6 @@ } } -// 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) - { - if (*fmt) - { - size_t len = strlen (fmt); - - 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; - } - - 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) { @@ -411,7 +368,8 @@ 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 @@ -445,38 +403,52 @@ } 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; + // 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. - error_1 (std::cerr, "error", id, fmt, args, with_cfn); + if (fmt) + { + if (*fmt) + { + size_t len = strlen (fmt); - if (error_state != -2 && ! symbol_table::at_top_level () - && ! discard_error_messages) - pr_where ("error"); + 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); - if ((interactive || forced_interactive) - && Vdebug_on_error && init_state == 0 - && octave_call_stack::caller_user_code ()) - { - unwind_protect frame; - frame.protect_var (Vdebug_on_error); - Vdebug_on_error = false; + if (! symbol_table::at_top_level () + && ! discard_error_messages) + pr_where ("error"); + } + } + } + } + else + panic ("error_1: invalid format"); - 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 @@ -491,7 +463,7 @@ void verror_with_cfn (const char *fmt, va_list args) { - error_2 ("", fmt, args, true); + error_1 (std::cerr, "error", "", fmt, args, true); } void @@ -506,7 +478,7 @@ 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 @@ -521,7 +493,7 @@ 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 @@ -635,7 +607,7 @@ { // Handle this warning as an error. - error_2 (id, fmt, args); + error_1 (std::cerr, "error", id, fmt, args); } else if (warn_opt == 1) { @@ -643,12 +615,9 @@ if (! symbol_table::at_top_level () && Vbacktrace_on_warning - && ! warning_state && ! discard_warning_messages) pr_where ("warning"); - warning_state = 1; - if ((interactive || forced_interactive) && Vdebug_on_warning && octave_call_stack::caller_user_code ()) @@ -850,120 +819,117 @@ { 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; } @@ -988,31 +954,28 @@ { 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"; } } @@ -1154,12 +1117,7 @@ // 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); @@ -1183,6 +1141,8 @@ octave_idx_type nel = ident.numel (); + assert (nel != 0); + bool found = false; std::string val; @@ -1210,13 +1170,14 @@ } } - 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; } @@ -1294,70 +1255,200 @@ { string_vector argv = args.make_argv ("warning"); - if (! error_state) + std::string arg1 = argv(1); + std::string arg2 = "all"; + + if (argc >= 3) + arg2 = argv(2); + + if (arg1 == "on" || arg1 == "off" || arg1 == "error") { - std::string arg1 = argv(1); - std::string arg2 = "all"; + octave_map old_warning_options = warning_options; - if (argc >= 3) - arg2 = argv(2); + if (argc == 4 && argv(3) == "local" + && ! symbol_table::at_top_level ()) + { + symbol_table::scope_id scope + = octave_call_stack::current_scope (); - if (arg1 == "on" || arg1 == "off" || arg1 == "error") + symbol_table::context_id context + = octave_call_stack::current_context (); + + octave_scalar_map val = warning_query (arg2); + + octave_value curr_state = val.contents ("state"); + + // FIXME: this might be better with a dictionary object. + + octave_value curr_warning_states + = symbol_table::varval (".saved_warning_states.", + scope, context); + + octave_map m; + + if (curr_warning_states.is_defined ()) + m = curr_warning_states.map_value (); + else + { + string_vector fields (2); + + fields(0) = "identifier"; + fields(1) = "state"; + + m = octave_map (dim_vector (0, 1), fields); + } + + Cell ids = m.contents ("identifier"); + Cell states = m.contents ("state"); + + octave_idx_type nel = states.numel (); + bool found = false; + octave_idx_type i; + for (i = 0; i < nel; i++) + { + std::string id = ids(i).string_value (); + + if (id == arg2) + { + states(i) = curr_state; + found = true; + break; + } + } + + if (! found) + { + m.resize (dim_vector (nel+1, 1)); + + ids.resize (dim_vector (nel+1, 1)); + states.resize (dim_vector (nel+1, 1)); + + ids(nel) = arg2; + states(nel) = curr_state; + } + + m.contents ("identifier") = ids; + m.contents ("state") = states; + + symbol_table::assign + (".saved_warning_states.", m, scope, context); + + // Now ignore the "local" argument and continue to + // handle the current setting. + argc--; + } + + if (arg2 == "all") { - octave_map old_warning_options = warning_options; + octave_map tmp; - if (argc == 4 && argv(3) == "local" - && ! symbol_table::at_top_level ()) + Cell id (1, 1); + Cell st (1, 1); + + id(0) = arg2; + st(0) = arg1; + + // Since internal Octave functions are not + // compatible, turning all warnings into errors + // should leave the state of + // Octave:matlab-incompatible alone. + + if (arg1 == "error" + && warning_options.contains ("identifier")) { - symbol_table::scope_id scope - = octave_call_stack::current_scope (); + octave_idx_type n = 1; - symbol_table::context_id context - = octave_call_stack::current_context (); + Cell tid = warning_options.contents ("identifier"); + Cell tst = warning_options.contents ("state"); - octave_scalar_map val = warning_query (arg2); + for (octave_idx_type i = 0; i < tid.numel (); i++) + { + octave_value vid = tid(i); - octave_value curr_state = val.contents ("state"); + if (vid.is_string ()) + { + std::string key = vid.string_value (); - // FIXME: this might be better with a dictionary object. + if (key == "Octave:matlab-incompatible" + || key == "Octave:single-quote-string") + { + id.resize (dim_vector (1, n+1)); + st.resize (dim_vector (1, n+1)); - octave_value curr_warning_states - = symbol_table::varval (".saved_warning_states.", - scope, context); + id(n) = tid(i); + st(n) = tst(i); - octave_map m; + n++; + } + } + } + } - if (curr_warning_states.is_defined ()) - m = curr_warning_states.map_value (); - else + tmp.assign ("identifier", id); + tmp.assign ("state", st); + + warning_options = tmp; + + done = true; + } + else if (arg2 == "backtrace") + { + if (arg1 != "error") + { + Vbacktrace_on_warning = (arg1 == "on"); + done = true; + } + } + else if (arg2 == "debug") + { + if (arg1 != "error") + { + Vdebug_on_warning = (arg1 == "on"); + done = true; + } + } + else if (arg2 == "verbose") + { + if (arg1 != "error") + { + Vverbose_warning = (arg1 == "on"); + done = true; + } + } + else if (arg2 == "quiet") + { + if (arg1 != "error") + { + Vquiet_warning = (arg1 == "on"); + done = true; + } + } + else + { + if (arg2 == "last") + arg2 = Vlast_warning_id; + + if (arg2 == "all") + initialize_warning_options (arg1); + else + { + Cell ident = warning_options.contents ("identifier"); + Cell state = warning_options.contents ("state"); + + octave_idx_type nel = ident.numel (); + + bool found = false; + + for (octave_idx_type i = 0; i < nel; i++) { - string_vector fields (2); + if (ident(i).string_value () == arg2) + { + // FIXME: if state for "all" is same as arg1, + // we can simply remove the item + // from the list. - fields(0) = "identifier"; - fields(1) = "state"; - - m = octave_map (dim_vector (0, 1), fields); - } - - if (error_state) - panic_impossible (); - - Cell ids = m.contents ("identifier"); - Cell states = m.contents ("state"); - - octave_idx_type nel = states.numel (); - bool found = false; - octave_idx_type i; - for (i = 0; i < nel; i++) - { - std::string id = ids(i).string_value (); - - if (error_state) - panic_impossible (); - - if (id == arg2) - { - states(i) = curr_state; + state(i) = arg1; + warning_options.assign ("state", state); found = true; break; } @@ -1365,191 +1456,52 @@ if (! found) { - m.resize (dim_vector (nel+1, 1)); + // FIXME: if state for "all" is same as arg1, + // we don't need to do anything. - ids.resize (dim_vector (nel+1, 1)); - states.resize (dim_vector (nel+1, 1)); + ident.resize (dim_vector (1, nel+1)); + state.resize (dim_vector (1, nel+1)); - ids(nel) = arg2; - states(nel) = curr_state; - } + ident(nel) = arg2; + state(nel) = arg1; - m.contents ("identifier") = ids; - m.contents ("state") = states; + warning_options.clear (); - symbol_table::assign - (".saved_warning_states.", m, scope, context); - - // Now ignore the "local" argument and continue to - // handle the current setting. - argc--; - } - - if (arg2 == "all") - { - octave_map tmp; - - Cell id (1, 1); - Cell st (1, 1); - - id(0) = arg2; - st(0) = arg1; - - // Since internal Octave functions are not - // compatible, turning all warnings into errors - // should leave the state of - // Octave:matlab-incompatible alone. - - if (arg1 == "error" - && warning_options.contains ("identifier")) - { - octave_idx_type n = 1; - - Cell tid = warning_options.contents ("identifier"); - Cell tst = warning_options.contents ("state"); - - for (octave_idx_type i = 0; i < tid.numel (); i++) - { - octave_value vid = tid(i); - - if (vid.is_string ()) - { - std::string key = vid.string_value (); - - if (key == "Octave:matlab-incompatible" - || key == "Octave:single-quote-string") - { - id.resize (dim_vector (1, n+1)); - st.resize (dim_vector (1, n+1)); - - id(n) = tid(i); - st(n) = tst(i); - - n++; - } - } - } - } - - tmp.assign ("identifier", id); - tmp.assign ("state", st); - - warning_options = tmp; - - done = true; - } - else if (arg2 == "backtrace") - { - if (arg1 != "error") - { - Vbacktrace_on_warning = (arg1 == "on"); - done = true; + warning_options.assign ("identifier", ident); + warning_options.assign ("state", state); } } - else if (arg2 == "debug") - { - if (arg1 != "error") - { - Vdebug_on_warning = (arg1 == "on"); - done = true; - } - } - else if (arg2 == "verbose") - { - if (arg1 != "error") - { - Vverbose_warning = (arg1 == "on"); - done = true; - } - } - else if (arg2 == "quiet") - { - if (arg1 != "error") - { - Vquiet_warning = (arg1 == "on"); - done = true; - } - } - else - { - if (arg2 == "last") - arg2 = Vlast_warning_id; - - if (arg2 == "all") - initialize_warning_options (arg1); - else - { - Cell ident = warning_options.contents ("identifier"); - Cell state = warning_options.contents ("state"); - - octave_idx_type nel = ident.numel (); - - bool found = false; - - for (octave_idx_type i = 0; i < nel; i++) - { - if (ident(i).string_value () == arg2) - { - // FIXME: if state for "all" is same as arg1, - // we can simply remove the item - // from the list. - - state(i) = arg1; - warning_options.assign ("state", state); - found = true; - break; - } - } - - if (! found) - { - // FIXME: if state for "all" is same as arg1, - // we don't need to do anything. - - ident.resize (dim_vector (1, nel+1)); - state.resize (dim_vector (1, nel+1)); - - ident(nel) = arg2; - state(nel) = arg1; - - warning_options.clear (); - - warning_options.assign ("identifier", ident); - warning_options.assign ("state", state); - } - } - - done = true; - } - - if (done && nargout > 0) - retval = old_warning_options; - } - else if (arg1 == "query") - { - if (arg2 == "all") - retval = warning_options; - else if (arg2 == "backtrace" || arg2 == "debug" - || arg2 == "verbose" || arg2 == "quiet") - { - octave_scalar_map tmp; - tmp.assign ("identifier", arg2); - if (arg2 == "backtrace") - tmp.assign ("state", Vbacktrace_on_warning ? "on" : "off"); - else if (arg2 == "debug") - tmp.assign ("state", Vdebug_on_warning ? "on" : "off"); - else if (arg2 == "verbose") - tmp.assign ("state", Vverbose_warning ? "on" : "off"); - else - tmp.assign ("state", Vquiet_warning ? "on" : "off"); - - retval = tmp; - } - else - retval = warning_query (arg2); done = true; } + + if (done && nargout > 0) + retval = old_warning_options; + } + else if (arg1 == "query") + { + if (arg2 == "all") + retval = warning_options; + else if (arg2 == "backtrace" || arg2 == "debug" + || arg2 == "verbose" || arg2 == "quiet") + { + octave_scalar_map tmp; + tmp.assign ("identifier", arg2); + if (arg2 == "backtrace") + tmp.assign ("state", Vbacktrace_on_warning ? "on" : "off"); + else if (arg2 == "debug") + tmp.assign ("state", Vdebug_on_warning ? "on" : "off"); + else if (arg2 == "verbose") + tmp.assign ("state", Vverbose_warning ? "on" : "off"); + else + tmp.assign ("state", Vquiet_warning ? "on" : "off"); + + retval = tmp; + } + else + retval = warning_query (arg2); + + done = true; } } else if (argc == 1) @@ -1569,7 +1521,69 @@ octave_map m = arg.map_value (); if (m.contains ("identifier") && m.contains ("state")) - warning_options = m; + { + // Ensure that we preserve the old state for "all". + + Cell ident = m.contents ("identifier"); + Cell state = m.contents ("state"); + + octave_idx_type nel = ident.numel (); + + bool found = false; + + for (octave_idx_type i = 0; i < nel; i++) + { + if (ident(i).string_value () == "all") + { + found = true; + break; + } + } + + if (! found) + { + ident.resize (dim_vector (1, nel+1)); + state.resize (dim_vector (1, nel+1)); + + for (octave_idx_type i = nel; i > 0; i--) + { + ident(i) = ident(i-1); + state(i) = state(i-1); + } + + Cell tid = warning_options.contents ("identifier"); + Cell tst = warning_options.contents ("state"); + + nel = tid.numel (); + + found = false; + + for (octave_idx_type i = 0; i < nel; i++) + { + if (tid(i).string_value () == "all") + { + ident(0) = "all"; + state(0) = tst(i).string_value (); + found = true; + break; + } + } + + // 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); + + m.clear (); + + m.assign ("identifier", ident); + m.assign ("state", state); + } + + warning_options = m; + } else error ("warning: expecting structure with fields 'identifier' and 'state'"); @@ -1580,7 +1594,7 @@ } } - if (! (error_state || done)) + if (! done) { octave_value_list nargs = args; @@ -1588,9 +1602,6 @@ bool have_fmt = maybe_extract_message_id ("warning", args, nargs, id); - if (error_state) - return retval; - std::string prev_msg = Vlast_warning_message; std::string curr_msg = handle_message (warning_with_id, id.c_str (), @@ -1696,11 +1707,6 @@ 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; @@ -1735,47 +1741,47 @@ 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 (); @@ -1783,35 +1789,31 @@ } } - 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 (); @@ -1833,36 +1835,26 @@ { 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 (); @@ -1890,26 +1882,20 @@ { 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 (); @@ -2036,7 +2022,6 @@ 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 @@ } 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 @@ 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 @@ 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_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 @@ { // 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 @@ -95,8 +95,6 @@ { // 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) 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 @@ 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 @@ -3099,9 +3099,20 @@ 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 @@ -3132,13 +3143,7 @@ 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 @@ -3157,14 +3162,19 @@ 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/svd.cc b/libinterp/corefcn/svd.cc --- a/libinterp/corefcn/svd.cc +++ b/libinterp/corefcn/svd.cc @@ -129,10 +129,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ { 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 @@ -646,8 +646,6 @@ catch (octave_execution_exception) { recover_from_exception (); - std::cerr << "error: unhandled execution exception -- trying to return to prompt" - << std::endl; } catch (std::bad_alloc) { diff --git a/libinterp/corefcn/toplev.h b/libinterp/corefcn/toplev.h --- a/libinterp/corefcn/toplev.h +++ b/libinterp/corefcn/toplev.h @@ -518,9 +518,6 @@ OCTAVE_IGNORE_EXCEPTION (octave_interrupt_exception) \ OCTAVE_IGNORE_EXCEPTION (octave_execution_exception) \ OCTAVE_IGNORE_EXCEPTION (std::bad_alloc) \ - \ - if (error_state) \ - error_state = 0; \ } \ while (0) diff --git a/libinterp/corefcn/variables.cc b/libinterp/corefcn/variables.cc --- a/libinterp/corefcn/variables.cc +++ b/libinterp/corefcn/variables.cc @@ -271,7 +271,6 @@ 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); @@ -379,9 +378,14 @@ 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 @@ -686,7 +686,6 @@ catch (Magick::Exception& e) { error ("Magick++ exception: %s", e.what ()); - error_state = 1; } } @@ -1376,7 +1375,6 @@ 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 @@ -125,29 +125,22 @@ 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 @@ 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 @@ -2045,8 +2045,18 @@ 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 @@ -146,18 +146,11 @@ 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,10 +78,6 @@ frame.protect_var (quit_allowed); quit_allowed = false; - // Clear errors. - frame.protect_var (error_state); - error_state = 0; - try { // Run the actual code. @@ -92,15 +88,16 @@ // 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 @@ -1491,16 +1491,9 @@ 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 { @@ -1994,14 +1987,7 @@ 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), @@ -2016,16 +2002,7 @@ = 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 @@ 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 @@ = 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 @@ = 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 @@ = 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; @@ -2426,16 +2367,7 @@ = 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 ()); @@ -2449,16 +2381,7 @@ = 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; @@ -2520,14 +2443,7 @@ { make_unique (); - try - { - f (*rep); - } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } + f (*rep); } else { @@ -2548,14 +2464,7 @@ 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; @@ -2595,16 +2504,7 @@ 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/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 @@ -2049,7 +2049,6 @@ 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); @@ -2070,7 +2069,7 @@ { 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 ()); @@ -3602,7 +3601,6 @@ 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); @@ -3614,7 +3612,7 @@ { 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 (), @@ -4794,13 +4792,21 @@ 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(). @@ -4811,8 +4817,16 @@ 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 (); @@ -4952,16 +4966,22 @@ 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(). @@ -4972,6 +4992,17 @@ 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::quiet_breakpoint_flag = false; +bool tree_evaluator::unwind_protect_exception = false; + tree_evaluator::stmt_list_type tree_evaluator::statement_context = tree_evaluator::other; @@ -751,10 +753,6 @@ // result_values(0) = tmp_result; } } - catch (octave_execution_exception) - { - gripe_library_execution_error (); - } catch (std::bad_alloc) { // FIXME: We want to use error_with_id here so that we set @@ -902,15 +900,22 @@ 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 @@ 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 @@ 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 @@ 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,26 @@ // 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) + octave_throw_execution_exception (); } void @@ -1040,15 +1042,20 @@ if (unwind_protect_code) { + unwind_protect_exception = false; + try { unwind_protect_code->accept (*this); } catch (...) { + 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 @@ static bool quiet_breakpoint_flag; + static bool unwind_protect_exception; + // Possible types of evaluation contexts. enum stmt_list_type { 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 @@ -156,7 +156,7 @@ %! 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 @@ -157,7 +157,7 @@ %! skewness (1); %! assert (lastwarn (), ""); %! unwind_protect_cleanup -%! warning (wstate, "Octave:divide-by-zero"); +%! warning (wstate); %! end_unwind_protect ## Test input validation diff --git a/scripts/testfun/test.m b/scripts/testfun/test.m --- a/scripts/testfun/test.m +++ b/scripts/testfun/test.m @@ -471,11 +471,6 @@ lasterr (""); lastwarn (""); try - ## FIXME: lastwarn () must be called once from *WITHIN* the try block - ## or subsequent warning/lastwarn statements may fail. - ## Likely this is something to do with the specialness of - ## the try block which is disabling normal errors. - lastwarn (); eval (sprintf ("__test__(%s);", __shared)); if (! __iswarning) __msg = [__signal_fail "error failed.\n" ...