Mercurial > hg > octave-nkf
changeset 20749:dd6345fd8a97
use exceptions for better invalid index error reporting (bug #45957)
* lo-array-gripes.h, lo-array-gripes.cc (index_exception):
New base class for indexing errors.
(invalid_index, out_of_range): New classes.
(gripe_index_out_of_range): New overloaded function.
(gripe_invalid_index): New overloaded functions.
Delete version with no arguments.
(gripe_invalid_assignment_size, gripe_assignment_dimension_mismatch):
Delete.
Change uses of gripe functions as needed.
* Cell.cc (Cell::index, Cell::assign, Cell::delete_elements): Use
exceptions to collect error info about and handle indexing errors.
* data.cc (Fnth_element, do_accumarray_sum, F__accumarray_sum__,
do_accumarray_minmax, do_accumarray_minmax_fun, F__accumdim_sum__):
Likewise.
* oct-map.cc (octave_map::index, octave_map::assign,
octave_map::delete_elements): Likewise.
* sparse.cc (Fsparse): Likewise.
* sub2ind.cc (Fsub2ind, Find2sub): Likewise. New tests.
* utils.cc (dims_to_numel): Likewise.
* ov-base-diag.cc (octave_base_diag<DMT, MT>::do_index_op,
octave_base_diag<DMT, MT>::subsasgn): Likewise.
* ov-base-mat.cc (octave_base_matrix<MT>::subsref,
octave_base_matrix<MT>::assign): Likewise.
* ov-base-sparse.cc (octave_base_sparse<T>::do_index_op,
octave_base_sparse<T>::assign,
octave_base_sparse<MT>::delete_elements): Likewise.
* ov-classdef.cc (cdef_object_array::subsref,
cdef_object_array::subsasgn): Likewise.
* ov-java.cc (make_java_index): Likewise.
* ov-perm.cc (octave_perm_matrix::do_index_op): Likewise.
* ov-range.cc (octave_range::do_index_op): Likewise.
* ov-re-diag.cc (octave_diag_matrix::do_index_op): Likewise.
* ov-str-mat.cc (octave_char_matrix_str::do_index_op_internal): Likewise.
* pt-assign.cc (tree_simple_assignment::rvalue1): Likewise.
* pt-idx.cc (tree_index_expression::rvalue,
tree_index_expression::lvalue): Likewise.
* Array-util.cc (sub2ind): Likewise.
* toplev.cc (main_loop): Also catch unhandled index_exception
exceptions.
* ov-base.cc (octave_base_value::index_vector): Improve error message.
* ov-re-sparse.cc (octave_sparse_matrix::index_vector): Likewise.
* ov-complex.cc (complex_index): New class.
(gripe_complex_index): New function.
(octave_complex::index_vector): Use it.
* pt-id.h, pt-id.cc (tree_identifier::is_variable,
tree_black_hole::is_variable): Now const.
* pt-idx.cc (final_index_error): New static function.
(tree_index_expression::rvalue, tree_index_expression::lvalue):
Use it.
* index.tst: New tests.
line wrap: on
line diff
--- a/libinterp/corefcn/Cell.cc +++ b/libinterp/corefcn/Cell.cc @@ -162,51 +162,66 @@ octave_idx_type n = idx_arg.length (); - switch (n) - { - case 0: - retval = *this; - break; + // If we catch an indexing error in index_vector, we flag an error + // in index k. Ensure it is the right value befor each idx_vector + // call. Same variable as used in for loop in default case. - case 1: - { - idx_vector i = idx_arg(0).index_vector (); + octave_idx_type k = 0; - if (! error_state) - retval = Array<octave_value>::index (i, resize_ok, Matrix ()); - } - break; + try + { + switch (n) + { + case 0: + retval = *this; + break; - case 2: - { - idx_vector i = idx_arg(0).index_vector (); + case 1: + { + idx_vector i = idx_arg(0).index_vector (); - if (! error_state) + if (! error_state) + retval = Array<octave_value>::index (i, resize_ok, Matrix ()); + } + break; + + case 2: { - idx_vector j = idx_arg(1).index_vector (); + idx_vector i = idx_arg(0).index_vector (); if (! error_state) - retval = Array<octave_value>::index (i, j, resize_ok, Matrix ()); - } - } - break; + { + k = 1; + idx_vector j = idx_arg(1).index_vector (); - default: - { - Array<idx_vector> iv (dim_vector (n, 1)); + if (! error_state) + retval = Array<octave_value>::index (i, j, resize_ok, Matrix ()); + } + } + break; - for (octave_idx_type i = 0; i < n; i++) + default: { - iv(i) = idx_arg(i).index_vector (); + Array<idx_vector> iv (dim_vector (n, 1)); + + for (k = 0; k < n; k++) + { + iv(k) = idx_arg(k).index_vector (); - if (error_state) - break; + if (error_state) + break; + } + if (!error_state) + retval = Array<octave_value>::index (iv, resize_ok, Matrix ()); } - - if (!error_state) - retval = Array<octave_value>::index (iv, resize_ok, Matrix ()); - } - break; + break; + } + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (n, k+1); + throw; } return retval; @@ -228,7 +243,18 @@ Array<idx_vector> ra_idx (dim_vector (len, 1)); for (octave_idx_type i = 0; i < len; i++) - ra_idx(i) = idx_arg(i).index_vector (); + { + try + { + ra_idx(i) = idx_arg(i).index_vector (); + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos (len, i+1); + throw; + } + } Array<octave_value>::assign (ra_idx, rhs, fill_val); } @@ -242,7 +268,16 @@ Array<idx_vector> ra_idx (dim_vector (len, 1)); for (octave_idx_type i = 0; i < len; i++) - ra_idx.xelem (i) = idx_arg(i).index_vector (); + try + { + ra_idx.xelem (i) = idx_arg(i).index_vector (); + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos (len, i+1); + throw; + } Array<octave_value>::delete_elements (ra_idx); }
--- a/libinterp/corefcn/data.cc +++ b/libinterp/corefcn/data.cc @@ -7244,44 +7244,51 @@ if (dim < 0) dim = argx.dims ().first_non_singleton (); - idx_vector n = args(1).index_vector (); - - if (error_state) - return retval; - - switch (argx.builtin_type ()) + try { - case btyp_double: - retval = argx.array_value ().nth_element (n, dim); - break; - case btyp_float: - retval = argx.float_array_value ().nth_element (n, dim); - break; - case btyp_complex: - retval = argx.complex_array_value ().nth_element (n, dim); - break; - case btyp_float_complex: - retval = argx.float_complex_array_value ().nth_element (n, dim); - break; + idx_vector n = args(1).index_vector (); + + if (error_state) + return retval; + + switch (argx.builtin_type ()) + { + case btyp_double: + retval = argx.array_value ().nth_element (n, dim); + break; + case btyp_float: + retval = argx.float_array_value ().nth_element (n, dim); + break; + case btyp_complex: + retval = argx.complex_array_value ().nth_element (n, dim); + break; + case btyp_float_complex: + retval = argx.float_complex_array_value ().nth_element (n, dim); + break; #define MAKE_INT_BRANCH(X) \ - case btyp_ ## X: \ - retval = argx.X ## _array_value ().nth_element (n, dim); \ - break; - - MAKE_INT_BRANCH (int8); - MAKE_INT_BRANCH (int16); - MAKE_INT_BRANCH (int32); - MAKE_INT_BRANCH (int64); - MAKE_INT_BRANCH (uint8); - MAKE_INT_BRANCH (uint16); - MAKE_INT_BRANCH (uint32); - MAKE_INT_BRANCH (uint64); + case btyp_ ## X: \ + retval = argx.X ## _array_value ().nth_element (n, dim); \ + break; + + MAKE_INT_BRANCH (int8); + MAKE_INT_BRANCH (int16); + MAKE_INT_BRANCH (int32); + MAKE_INT_BRANCH (int64); + MAKE_INT_BRANCH (uint8); + MAKE_INT_BRANCH (uint16); + MAKE_INT_BRANCH (uint32); + MAKE_INT_BRANCH (uint64); #undef MAKE_INT_BRANCH - default: - if (argx.is_cellstr ()) - retval = argx.cellstr_value ().nth_element (n, dim); - else - gripe_wrong_type_arg ("nth_element", argx); + default: + if (argx.is_cellstr ()) + retval = argx.cellstr_value ().nth_element (n, dim); + else + gripe_wrong_type_arg ("nth_element", argx); + } + } + catch (index_exception& e) + { + error ("nth_element: invalid N value %s. %s", e.idx (), e.explain ()); } } else @@ -7323,42 +7330,50 @@ int nargin = args.length (); if (nargin >= 2 && nargin <= 3 && args(0).is_numeric_type ()) { - idx_vector idx = args(0).index_vector (); - octave_idx_type n = -1; - if (nargin == 3) - n = args(2).idx_type_value (true); - - if (! error_state) + try { - octave_value vals = args(1); - if (vals.is_range ()) - { - Range r = vals.range_value (); - if (r.inc () == 0) - vals = r.base (); - } - - if (vals.is_single_type ()) + idx_vector idx = args(0).index_vector (); + octave_idx_type n = -1; + if (nargin == 3) + n = args(2).idx_type_value (true); + + if (! error_state) { - if (vals.is_complex_type ()) - retval = do_accumarray_sum (idx, - vals.float_complex_array_value (), - n); + octave_value vals = args(1); + if (vals.is_range ()) + { + Range r = vals.range_value (); + if (r.inc () == 0) + vals = r.base (); + } + + if (vals.is_single_type ()) + { + if (vals.is_complex_type ()) + retval = do_accumarray_sum (idx, + vals.float_complex_array_value (), + n); + else + retval = do_accumarray_sum (idx, vals.float_array_value (), n); + } + else if (vals.is_numeric_type () || vals.is_bool_type ()) + { + if (vals.is_complex_type ()) + retval = do_accumarray_sum (idx, + vals.complex_array_value (), + n); + else + retval = do_accumarray_sum (idx, vals.array_value (), n); + } else - retval = do_accumarray_sum (idx, vals.float_array_value (), n); + gripe_wrong_type_arg ("accumarray", vals); } - else if (vals.is_numeric_type () || vals.is_bool_type ()) - { - if (vals.is_complex_type ()) - retval = do_accumarray_sum (idx, - vals.complex_array_value (), - n); - else - retval = do_accumarray_sum (idx, vals.array_value (), n); - } - else - gripe_wrong_type_arg ("accumarray", vals); - } + } + catch (index_exception& e) + { + error ("__accumarray_sum__: invalid IDX %s. %s", + e.idx(), e.explain ()); + } } else print_usage (); @@ -7403,60 +7418,69 @@ int nargin = args.length (); if (nargin >= 3 && nargin <= 4 && args(0).is_numeric_type ()) { - idx_vector idx = args(0).index_vector (); - octave_idx_type n = -1; - if (nargin == 4) - n = args(3).idx_type_value (true); - - if (! error_state) + try { - octave_value vals = args(1); - octave_value zero = args(2); - - switch (vals.builtin_type ()) + idx_vector idx = args(0).index_vector (); + octave_idx_type n = -1; + if (nargin == 4) + n = args(3).idx_type_value (true); + + if (! error_state) { - case btyp_double: - retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin, - zero.double_value ()); - break; - case btyp_float: - retval = do_accumarray_minmax (idx, vals.float_array_value (), n, - ismin, zero.float_value ()); - break; - case btyp_complex: - retval = do_accumarray_minmax (idx, vals.complex_array_value (), - n, ismin, zero.complex_value ()); - break; - case btyp_float_complex: - retval = do_accumarray_minmax (idx, - vals.float_complex_array_value (), - n, ismin, - zero.float_complex_value ()); - break; + octave_value vals = args(1); + octave_value zero = args(2); + + switch (vals.builtin_type ()) + { + case btyp_double: + retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin, + zero.double_value ()); + break; + case btyp_float: + retval = do_accumarray_minmax (idx, vals.float_array_value (), n, + ismin, zero.float_value ()); + break; + case btyp_complex: + retval = do_accumarray_minmax (idx, vals.complex_array_value (), + n, ismin, zero.complex_value ()); + break; + case btyp_float_complex: + retval = do_accumarray_minmax (idx, + vals.float_complex_array_value (), + n, ismin, + zero.float_complex_value ()); + break; #define MAKE_INT_BRANCH(X) \ - case btyp_ ## X: \ - retval = do_accumarray_minmax (idx, vals.X ## _array_value (), \ - n, ismin, \ - zero.X ## _scalar_value ()); \ - break; - - MAKE_INT_BRANCH (int8); - MAKE_INT_BRANCH (int16); - MAKE_INT_BRANCH (int32); - MAKE_INT_BRANCH (int64); - MAKE_INT_BRANCH (uint8); - MAKE_INT_BRANCH (uint16); - MAKE_INT_BRANCH (uint32); - MAKE_INT_BRANCH (uint64); + case btyp_ ## X: \ + retval = do_accumarray_minmax (idx, vals.X ## _array_value (), \ + n, ismin, \ + zero.X ## _scalar_value ()); \ + break; + + MAKE_INT_BRANCH (int8); + MAKE_INT_BRANCH (int16); + MAKE_INT_BRANCH (int32); + MAKE_INT_BRANCH (int64); + MAKE_INT_BRANCH (uint8); + MAKE_INT_BRANCH (uint16); + MAKE_INT_BRANCH (uint32); + MAKE_INT_BRANCH (uint64); #undef MAKE_INT_BRANCH - case btyp_bool: - retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin, - zero.bool_value ()); - break; - default: - gripe_wrong_type_arg ("accumarray", vals); + case btyp_bool: + retval = do_accumarray_minmax (idx, vals.array_value (), n, ismin, + zero.bool_value ()); + break; + default: + gripe_wrong_type_arg ("accumarray", vals); + } } } + catch (index_exception& e) + { + error ("do_accumarray_minmax_fun: invalid index %s. %s", + e.idx (), e.explain ()); + } + } else print_usage (); @@ -7523,39 +7547,46 @@ int nargin = args.length (); if (nargin >= 2 && nargin <= 4 && args(0).is_numeric_type ()) { - idx_vector idx = args(0).index_vector (); - int dim = -1; - if (nargin >= 3) - dim = args(2).int_value () - 1; - - octave_idx_type n = -1; - if (nargin == 4) - n = args(3).idx_type_value (true); - - if (! error_state) + try { - octave_value vals = args(1); - - if (vals.is_single_type ()) + idx_vector idx = args(0).index_vector (); + int dim = -1; + if (nargin >= 3) + dim = args(2).int_value () - 1; + + octave_idx_type n = -1; + if (nargin == 4) + n = args(3).idx_type_value (true); + + if (! error_state) { - if (vals.is_complex_type ()) - retval = do_accumdim_sum (idx, - vals.float_complex_array_value (), - dim, n); + octave_value vals = args(1); + + if (vals.is_single_type ()) + { + if (vals.is_complex_type ()) + retval = do_accumdim_sum (idx, + vals.float_complex_array_value (), + dim, n); + else + retval = do_accumdim_sum (idx, vals.float_array_value (), + dim, n); + } + else if (vals.is_numeric_type () || vals.is_bool_type ()) + { + if (vals.is_complex_type ()) + retval = do_accumdim_sum (idx, vals.complex_array_value (), + dim, n); + else + retval = do_accumdim_sum (idx, vals.array_value (), dim, n); + } else - retval = do_accumdim_sum (idx, vals.float_array_value (), - dim, n); + gripe_wrong_type_arg ("accumdim", vals); } - else if (vals.is_numeric_type () || vals.is_bool_type ()) - { - if (vals.is_complex_type ()) - retval = do_accumdim_sum (idx, vals.complex_array_value (), - dim, n); - else - retval = do_accumdim_sum (idx, vals.array_value (), dim, n); - } - else - gripe_wrong_type_arg ("accumdim", vals); + } + catch (index_exception& e) + { + error ("__accumdim_sum__: invalid IDX %s. %s", e.idx(), e.explain ()); } } else
--- a/libinterp/corefcn/find.cc +++ b/libinterp/corefcn/find.cc @@ -455,6 +455,11 @@ { // This case is equivalent to extracting indices from a logical // matrix. Try to reuse the possibly cached index vector. + + // No need to catch index_exception, since arg is bool. + // Out-of-range errors have already set pos, and will be + // caught later. + retval(0) = arg.index_vector ().unmask (); } else
--- a/libinterp/corefcn/oct-map.cc +++ b/libinterp/corefcn/oct-map.cc @@ -900,46 +900,62 @@ octave_idx_type n_idx = idx.length (); octave_map retval; - switch (n_idx) + // If we catch an indexing error in index_vector, we flag an error in + // index k. Ensure it is the right value befor each idx_vector call. + // Same variable as used in the for loop in the default case. + + octave_idx_type k = 0; + + try { - case 1: - { - idx_vector i = idx(0).index_vector (); + switch (n_idx) + { + case 1: + { + idx_vector i = idx(0).index_vector (); - if (! error_state) - retval = index (i, resize_ok); - } - break; + if (! error_state) + retval = index (i, resize_ok); + } + break; - case 2: - { - idx_vector i = idx(0).index_vector (); + case 2: + { + idx_vector i = idx(0).index_vector (); - if (! error_state) - { - idx_vector j = idx(1).index_vector (); + if (! error_state) + { + k = 1; + idx_vector j = idx(1).index_vector (); - retval = index (i, j, resize_ok); + retval = index (i, j, resize_ok); + } } - } - break; + break; - default: - { - Array<idx_vector> ia (dim_vector (n_idx, 1)); - - for (octave_idx_type i = 0; i < n_idx; i++) + default: { - ia(i) = idx(i).index_vector (); + Array<idx_vector> ia (dim_vector (n_idx, 1)); + + for (k = 0; k < n_idx; k++) + { + ia(k) = idx(k).index_vector (); - if (error_state) - break; + if (error_state) + break; + } + + if (! error_state) + retval = index (ia, resize_ok); } - - if (! error_state) - retval = index (ia, resize_ok); - } - break; + break; + } + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (n_idx, k+1); + throw; } return retval; @@ -1094,46 +1110,62 @@ { octave_idx_type n_idx = idx.length (); - switch (n_idx) + // If we catch an indexing error in index_vector, we flag an error in + // index k. Ensure it is the right value befor each idx_vector call. + // Same variable as used in the for loop in the default case. + + octave_idx_type k = 0; + + try { - case 1: - { - idx_vector i = idx(0).index_vector (); + switch (n_idx) + { + case 1: + { + idx_vector i = idx(0).index_vector (); - if (! error_state) - assign (i, rhs); - } - break; + if (! error_state) + assign (i, rhs); + } + break; - case 2: - { - idx_vector i = idx(0).index_vector (); + case 2: + { + idx_vector i = idx(0).index_vector (); - if (! error_state) - { - idx_vector j = idx(1).index_vector (); + if (! error_state) + { + k = 1; + idx_vector j = idx(1).index_vector (); - assign (i, j, rhs); + assign (i, j, rhs); + } } - } - break; + break; - default: - { - Array<idx_vector> ia (dim_vector (n_idx, 1)); - - for (octave_idx_type i = 0; i < n_idx; i++) + default: { - ia(i) = idx(i).index_vector (); + Array<idx_vector> ia (dim_vector (n_idx, 1)); + + for (k = 0; k < n_idx; k++) + { + ia(k) = idx(k).index_vector (); - if (error_state) - break; + if (error_state) + break; + } + + if (! error_state) + assign (ia, rhs); } - - if (! error_state) - assign (ia, rhs); - } - break; + break; + } + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (n_idx, k+1); + throw; } } @@ -1244,7 +1276,16 @@ for (octave_idx_type i = 0; i < n_idx; i++) { - ia(i) = idx(i).index_vector (); + try + { + ia(i) = idx(i).index_vector (); + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (n_idx, i+1); + throw; + } if (error_state) break;
--- a/libinterp/corefcn/sparse.cc +++ b/libinterp/corefcn/sparse.cc @@ -198,20 +198,31 @@ if (! error_state) { - idx_vector i = args(0).index_vector (); - idx_vector j = args(1).index_vector (); + int k = 0; // index we're checking when index_vector throws + try + { + idx_vector i = args(0).index_vector (); + k = 1; + idx_vector j = args(1).index_vector (); - if (args(2).is_bool_type ()) - retval = SparseBoolMatrix (args(2).bool_array_value (), i, j, + if (args(2).is_bool_type ()) + retval = SparseBoolMatrix (args(2).bool_array_value (), i,j, + m, n, summation, nzmax); + else if (args(2).is_complex_type ()) + retval = SparseComplexMatrix (args(2).complex_array_value(), + i, j, m, n, summation, nzmax); + else if (args(2).is_numeric_type ()) + retval = SparseMatrix (args(2).array_value (), i, j, m, n, summation, nzmax); - else if (args(2).is_complex_type ()) - retval = SparseComplexMatrix (args(2).complex_array_value (), - i, j, m, n, summation, nzmax); - else if (args(2).is_numeric_type ()) - retval = SparseMatrix (args(2).array_value (), i, j, - m, n, summation, nzmax); - else - gripe_wrong_type_arg ("sparse", args(2)); + else + gripe_wrong_type_arg ("sparse", args(2)); + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (2, k+1); + throw; + } } }
--- a/libinterp/corefcn/sub2ind.cc +++ b/libinterp/corefcn/sub2ind.cc @@ -99,11 +99,21 @@ { if (args(j+1).is_numeric_type ()) { - idxa(j) = args(j+1).index_vector (); - if (error_state) - break; - else if (j > 0 && args(j+1).dims () != args(1).dims ()) - error ("sub2ind: all subscripts must be of the same size"); + try + { + idxa(j) = args(j+1).index_vector (); + if (error_state) + break; + else if (j > 0 && args(j+1).dims () != args(1).dims ()) + error ("sub2ind: all subscripts must be of the same size"); + } + catch (index_exception& e) + { + e.set_pos_if_unset (nargin-1, j+1); + e.set_var (""); // no particular variable + (*current_liboctave_error_with_id_handler) + (e.id(), e.err()); + } } else error ("sub2ind: subscripts must be numeric"); @@ -134,23 +144,23 @@ # Test low index %!assert (sub2ind ([10 10 10], 1, 1, 1), 1) -%!error <subscript indices> sub2ind ([10 10 10], 0, 1, 1) -%!error <subscript indices> sub2ind ([10 10 10], 1, 0, 1) -%!error <subscript indices> sub2ind ([10 10 10], 1, 1, 0) +%!error <index \(0,_,_\)> sub2ind ([10 10 10], 0, 1, 1) +%!error <index \(_,0,_\)> sub2ind ([10 10 10], 1, 0, 1) +%!error <index \(_,_,0\)> sub2ind ([10 10 10], 1, 1, 0) # Test high index %!assert (sub2ind ([10 10 10], 10, 10, 10), 1000) -%!error <index out of range> sub2ind ([10 10 10], 11, 10, 10) -%!error <index out of range> sub2ind ([10 10 10], 10, 11, 10) -%!error <index out of range> sub2ind ([10 10 10], 10, 10, 11) +%!error <index \(11,_,_\); out of bound 10> sub2ind ([10 10 10], 11, 10, 10) +%!error <index \(_,11,_\); out of bound 10> sub2ind ([10 10 10], 10, 11, 10) +%!error <index \(_,_,11\); out of bound 10> sub2ind ([10 10 10], 10, 10, 11) # Test high index in the trailing dimensions %!assert (sub2ind ([10, 1], 2, 1, 1), 2) -%!error <index out of range> sub2ind ([10, 1], 1, 2, 1) -%!error <index out of range> sub2ind ([10, 1], 1, 1, 2) +%!error <index \(_,2,_\); out of bound 1> sub2ind ([10, 1], 1, 2, 1) +%!error <index \(_,_,2\); out of bound 1> sub2ind ([10, 1], 1, 1, 2) %!assert (sub2ind ([10 10], 2, 2, 1), 12) -%!error <index out of range> sub2ind ([10 10], 2, 1, 2) -%!error <index out of range> sub2ind ([10 10], 1, 2, 2) +%!error <index \(_,_,2\); out of bound 1> sub2ind ([10 10], 2, 1, 2) +%!error <index \(_,_,2\); out of bound 1> sub2ind ([10 10], 1, 2, 2) # Test handling of empty arguments %!assert (sub2ind ([10 10], zeros (0,0), zeros (0,0)), zeros (0,0)) @@ -164,8 +174,8 @@ ## Test input validation %!error <dimension vector> sub2ind ([10 10.5], 1, 1) -%!error <subscript indices> sub2ind ([10 10], 1.5, 1) -%!error <subscript indices> sub2ind ([10 10], 1, 1.5) +%!error <index \(1.5,_\)> sub2ind ([10 10], 1.5, 1) +%!error <index \(_,1.5\)> sub2ind ([10 10], 1, 1.5) */ DEFUN (ind2sub, args, nargout, @@ -195,14 +205,21 @@ else { dim_vector dv = get_dim_vector (args(0), "ind2sub"); - idx_vector idx = args(1).index_vector (); - if (! error_state) + try { - if (nargout > dv.length ()) - dv = dv.redim (nargout); + idx_vector idx = args(1).index_vector (); + if (! error_state) + { + if (nargout > dv.length ()) + dv = dv.redim (nargout); - Array<idx_vector> idxa = ind2sub (dv, idx); - retval = Array<octave_value> (idxa); + Array<idx_vector> idxa = ind2sub (dv, idx); + retval = Array<octave_value> (idxa); + } + } + catch (index_exception& e) + { + error ("ind2sub: Invalid index %s. %s", e.idx (), e.explain ()); } }
--- a/libinterp/corefcn/toplev.cc +++ b/libinterp/corefcn/toplev.cc @@ -658,6 +658,13 @@ if (quitting_gracefully) return exit_status; } + catch (index_exception& e) + { + recover_from_exception (); + std::cerr << "error: unhandled index exception: " + << e.err () << " -- trying to return to prompt" + << std::endl; + } catch (const octave_execution_exception&) { recover_from_exception ();
--- a/libinterp/corefcn/utils.cc +++ b/libinterp/corefcn/utils.cc @@ -1298,10 +1298,18 @@ retval *= idxi.numel (); else { - idx_vector jdx = idxi.index_vector (); - if (error_state) - break; - retval *= jdx.length (dv(i)); + try + { + idx_vector jdx = idxi.index_vector (); + if (error_state) + break; + retval *= jdx.length (dv(i)); + } + catch (index_exception& e) + { + error ("dims_to_numel: Invalid IDX %s. %s", + e.idx (), e.explain ()); + } } } }
--- a/libinterp/octave-value/ov-base-diag.cc +++ b/libinterp/octave-value/ov-base-diag.cc @@ -29,6 +29,7 @@ #include "mach-info.h" #include "lo-ieee.h" +#include "ov-base-diag.h" #include "mxarray.h" #include "ov-base.h" #include "ov-base-mat.h" @@ -103,26 +104,37 @@ if (idx.length () == 2 && ! resize_ok) { - idx_vector idx0 = idx(0).index_vector (); - idx_vector idx1 = idx(1).index_vector (); - - if (idx0.is_scalar () && idx1.is_scalar ()) - { - retval = matrix.checkelem (idx0(0), idx1(0)); - } - else + int k = 0; // index we're accesing when index_vector throws + try { - octave_idx_type m = idx0.length (matrix.rows ()); - octave_idx_type n = idx1.length (matrix.columns ()); - if (idx0.is_colon_equiv (m) && idx1.is_colon_equiv (n) - && m <= matrix.rows () && n <= matrix.rows ()) + idx_vector idx0 = idx(0).index_vector (); + k = 1; + idx_vector idx1 = idx(1).index_vector (); + + if (idx0.is_scalar () && idx1.is_scalar ()) { - DMT rm (matrix); - rm.resize (m, n); - retval = rm; + retval = matrix.checkelem (idx0(0), idx1(0)); } else - retval = to_dense ().do_index_op (idx, resize_ok); + { + octave_idx_type m = idx0.length (matrix.rows ()); + octave_idx_type n = idx1.length (matrix.columns ()); + if (idx0.is_colon_equiv (m) && idx1.is_colon_equiv (n) + && m <= matrix.rows () && n <= matrix.rows ()) + { + DMT rm (matrix); + rm.resize (m, n); + retval = rm; + } + else + retval = to_dense ().do_index_op (idx, resize_ok); + } + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (2, k+1); + throw; } } else @@ -153,17 +165,28 @@ && jdx(0).is_scalar_type () && jdx(1).is_scalar_type ()) { typename DMT::element_type val; - idx_vector i0 = jdx(0).index_vector (); - idx_vector i1 = jdx(1).index_vector (); - if (! error_state && i0(0) == i1(0) - && i0(0) < matrix.rows () && i1(0) < matrix.cols () - && chk_valid_scalar (rhs, val)) + int k = 0; + try { - matrix.dgelem (i0(0)) = val; - retval = this; - this->count++; - // invalidate cache - dense_cache = octave_value (); + idx_vector i0 = jdx(0).index_vector (); + k = 1; + idx_vector i1 = jdx(1).index_vector (); + if (! error_state && i0(0) == i1(0) + && i0(0) < matrix.rows () && i1(0) < matrix.cols () + && chk_valid_scalar (rhs, val)) + { + matrix.dgelem (i0(0)) = val; + retval = this; + this->count++; + // invalidate cache + dense_cache = octave_value (); + } + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (2, k+1); + throw; } }
--- a/libinterp/octave-value/ov-base-mat.cc +++ b/libinterp/octave-value/ov-base-mat.cc @@ -36,7 +36,7 @@ #include "ov-base-mat.h" #include "ov-base-scalar.h" #include "pr-output.h" - + template <class MT> octave_value octave_base_matrix<MT>::subsref (const std::string& type, @@ -140,72 +140,88 @@ int nd = matrix.ndims (); const MT& cmatrix = matrix; - switch (n_idx) - { - case 0: - retval = matrix; - break; + // If we catch an indexing error in index_vector, we flag an error in + // index k. Ensure it is the right value befor each idx_vector call. + // Same variable as used in the for loop in the default case. + + octave_idx_type k = 0; - case 1: - { - idx_vector i = idx (0).index_vector (); + try + { + switch (n_idx) + { + case 0: + retval = matrix; + break; - if (! error_state) + case 1: { - // optimize single scalar index. - if (! resize_ok && i.is_scalar ()) - retval = cmatrix.checkelem (i(0)); - else - retval = MT (matrix.index (i, resize_ok)); + idx_vector i = idx (0).index_vector (); + + if (! error_state) + { + // optimize single scalar index. + if (! resize_ok && i.is_scalar ()) + retval = cmatrix.checkelem (i(0)); + else + retval = MT (matrix.index (i, resize_ok)); + } } - } - break; + break; - case 2: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) + case 2: { - idx_vector j = idx (1).index_vector (); + idx_vector i = idx (0).index_vector (); if (! error_state) { - // optimize two scalar indices. - if (! resize_ok && i.is_scalar () && j.is_scalar ()) - retval = cmatrix.checkelem (i(0), j(0)); - else - retval = MT (matrix.index (i, j, resize_ok)); + k=1; + idx_vector j = idx (1).index_vector (); + + if (! error_state) + { + // optimize two scalar indices. + if (! resize_ok && i.is_scalar () && j.is_scalar ()) + retval = cmatrix.checkelem (i(0), j(0)); + else + retval = MT (matrix.index (i, j, resize_ok)); + } } } - } - break; + break; - default: - { - Array<idx_vector> idx_vec (dim_vector (n_idx, 1)); - bool scalar_opt = n_idx == nd && ! resize_ok; - const dim_vector dv = matrix.dims (); + default: + { + Array<idx_vector> idx_vec (dim_vector (n_idx, 1)); + bool scalar_opt = n_idx == nd && ! resize_ok; + const dim_vector dv = matrix.dims (); - for (octave_idx_type i = 0; i < n_idx; i++) - { - idx_vec(i) = idx(i).index_vector (); + for (k = 0; k < n_idx; k++) + { + idx_vec(k) = idx(k).index_vector (); + + if (error_state) + break; - if (error_state) - break; - - scalar_opt = (scalar_opt && idx_vec(i).is_scalar ()); - } + scalar_opt = (scalar_opt && idx_vec(k).is_scalar ()); + } - if (! error_state) - { - if (scalar_opt) - retval = cmatrix.checkelem (conv_to_int_array (idx_vec)); - else - retval = MT (matrix.index (idx_vec, resize_ok)); + if (! error_state) + { + if (scalar_opt) + retval = cmatrix.checkelem (conv_to_int_array (idx_vec)); + else + retval = MT (matrix.index (idx_vec, resize_ok)); + } } - } - break; + break; + } + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (n_idx, k+1); + throw; } return retval; @@ -217,51 +233,65 @@ { octave_idx_type n_idx = idx.length (); - switch (n_idx) - { - case 0: - panic_impossible (); - break; + // If we catch an indexing error in index_vector, we flag an error in + // index k. Ensure it is the right value befor each idx_vector call. + // Same variable as used in the for loop in the default case. - case 1: - { - idx_vector i = idx (0).index_vector (); + octave_idx_type k = 0; - if (! error_state) - matrix.assign (i, rhs); - } - break; + try + { + switch (n_idx) + { + case 0: + panic_impossible (); + break; - case 2: - { - idx_vector i = idx (0).index_vector (); + case 1: + { + idx_vector i = idx (0).index_vector (); - if (! error_state) - { - idx_vector j = idx (1).index_vector (); + if (! error_state) + matrix.assign (i, rhs); + } + break; + + case 2: + { + idx_vector i = idx (0).index_vector (); - if (! error_state) - matrix.assign (i, j, rhs); - } - } - break; + if (! error_state) + { + k = 1; + idx_vector j = idx (1).index_vector (); - default: - { - Array<idx_vector> idx_vec (dim_vector (n_idx, 1)); + if (! error_state) + matrix.assign (i, j, rhs); + } + } + break; + + default: + { + Array<idx_vector> idx_vec (dim_vector (n_idx, 1)); - for (octave_idx_type i = 0; i < n_idx; i++) - { - idx_vec(i) = idx(i).index_vector (); + for (k = 0; k < n_idx; k++) + { + idx_vec(k) = idx(k).index_vector (); + + if (error_state) + break; + } - if (error_state) - break; - } - - if (! error_state) - matrix.assign (idx_vec, rhs); - } - break; + if (! error_state) + matrix.assign (idx_vec, rhs); + } + break; + } + } + catch (index_exception& e) + { + gripe_invalid_index (e.idx(), n_idx, k+1); } // Clear cache. @@ -288,86 +318,100 @@ MT mrhs (dim_vector (1, 1), rhs); - switch (n_idx) - { - case 0: - panic_impossible (); - break; + // If we catch an indexing error in index_vector, we flag an error in + // index k. Ensure it is the right value befor each idx_vector call. + // Same variable as used in the for loop in the default case. + + octave_idx_type k = 0; - case 1: - { - idx_vector i = idx (0).index_vector (); + try + { + switch (n_idx) + { + case 0: + panic_impossible (); + break; - if (! error_state) + case 1: { - // optimize single scalar index. - if (i.is_scalar () && i(0) < matrix.numel ()) - matrix(i(0)) = rhs; - else - matrix.assign (i, mrhs); + idx_vector i = idx (0).index_vector (); + + if (! error_state) + { + // optimize single scalar index. + if (i.is_scalar () && i(0) < matrix.numel ()) + matrix(i(0)) = rhs; + else + matrix.assign (i, mrhs); + } } - } - break; + break; - case 2: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) + case 2: { - idx_vector j = idx (1).index_vector (); + idx_vector i = idx (0).index_vector (); if (! error_state) { - // optimize two scalar indices. - if (i.is_scalar () && j.is_scalar () && nd == 2 - && i(0) < matrix.rows () && j(0) < matrix.columns ()) - matrix(i(0), j(0)) = rhs; - else - matrix.assign (i, j, mrhs); + k = 1; + idx_vector j = idx (1).index_vector (); + + if (! error_state) + { + // optimize two scalar indices. + if (i.is_scalar () && j.is_scalar () && nd == 2 + && i(0) < matrix.rows () && j(0) < matrix.columns ()) + matrix(i(0), j(0)) = rhs; + else + matrix.assign (i, j, mrhs); + } } } - } - break; + break; - default: - { - Array<idx_vector> idx_vec (dim_vector (n_idx, 1)); - bool scalar_opt = n_idx == nd; - const dim_vector dv = matrix.dims ().redim (n_idx); + default: + { + Array<idx_vector> idx_vec (dim_vector (n_idx, 1)); + bool scalar_opt = n_idx == nd; + const dim_vector dv = matrix.dims ().redim (n_idx); - for (octave_idx_type i = 0; i < n_idx; i++) - { - idx_vec(i) = idx(i).index_vector (); + for (k = 0; k < n_idx; k++) + { + idx_vec(k) = idx(k).index_vector (); - if (error_state) - break; + if (error_state) + break; - scalar_opt = (scalar_opt && idx_vec(i).is_scalar () - && idx_vec(i)(0) < dv(i)); - } + scalar_opt = (scalar_opt && idx_vec(k).is_scalar () + && idx_vec(k)(0) < dv(k)); + } - if (! error_state) - { - if (scalar_opt) + if (! error_state) { - // optimize all scalar indices. Don't construct an index array, - // but rather calc a scalar index directly. - octave_idx_type k = 1; - octave_idx_type j = 0; - for (octave_idx_type i = 0; i < n_idx; i++) + if (scalar_opt) { - j += idx_vec(i)(0) * k; - k *= dv(i); + // optimize all scalar indices. Don't construct + // an index array, but rather calc a scalar index directly. + octave_idx_type n = 1; + octave_idx_type j = 0; + for (octave_idx_type i = 0; i < n_idx; i++) + { + j += idx_vec(i)(0) * n; + n *= dv (i); + } + matrix(j) = rhs; } - matrix(j) = rhs; + else + matrix.assign (idx_vec, mrhs); } - else - matrix.assign (idx_vec, mrhs); } - } - break; + break; + } } + catch (const index_exception& e) + { + gripe_invalid_index (e.idx(), n_idx, k+1); + } // Clear cache. clear_cached_info ();
--- a/libinterp/octave-value/ov-base-sparse.cc +++ b/libinterp/octave-value/ov-base-sparse.cc @@ -44,6 +44,8 @@ #include "pager.h" #include "utils.h" +#include "lo-array-gripes.h" + template <class T> octave_value octave_base_sparse<T>::do_index_op (const octave_value_list& idx, @@ -53,36 +55,52 @@ octave_idx_type n_idx = idx.length (); - switch (n_idx) - { - case 0: - retval = matrix; - break; + // If we catch an indexing error in index_vector, we flag an error in + // index k. Ensure it is the right value befor each idx_vector call. + // Same variable as used in the for loop in the default case. - case 1: - { - idx_vector i = idx (0).index_vector (); + octave_idx_type k = 0; - if (! error_state) - retval = octave_value (matrix.index (i, resize_ok)); - } - break; + try + { + switch (n_idx) + { + case 0: + retval = matrix; + break; - case 2: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) + case 1: { - idx_vector j = idx (1).index_vector (); + idx_vector i = idx (0).index_vector (); if (! error_state) - retval = octave_value (matrix.index (i, j, resize_ok)); + retval = octave_value (matrix.index (i, resize_ok)); } - } - break; - default: - error ("sparse indexing needs 1 or 2 indices"); + break; + + case 2: + { + idx_vector i = idx (0).index_vector (); + + if (! error_state) + { + k = 1; + idx_vector j = idx (1).index_vector (); + + if (! error_state) + retval = octave_value (matrix.index (i, j, resize_ok)); + } + } + break; + default: + error ("sparse indexing needs 1 or 2 indices"); + } + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (n_idx, k+1); + throw; } return retval; @@ -170,35 +188,50 @@ octave_idx_type len = idx.length (); - switch (len) - { - case 1: - { - idx_vector i = idx (0).index_vector (); + // If we catch an indexing error in index_vector, we flag an error in + // index k. Ensure it is the right value befor each idx_vector call. + // Same variable as used in the for loop in the default case. - if (! error_state) - matrix.assign (i, rhs); + octave_idx_type k = 0; - break; - } - - case 2: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) + try + { + switch (len) + { + case 1: { - idx_vector j = idx (1).index_vector (); + idx_vector i = idx (0).index_vector (); if (! error_state) - matrix.assign (i, j, rhs); + matrix.assign (i, rhs); + + break; } - break; - } + case 2: + { + idx_vector i = idx (0).index_vector (); + + if (! error_state) + { + k = 1; + idx_vector j = idx (1).index_vector (); - default: - error ("sparse indexing needs 1 or 2 indices"); + if (! error_state) + matrix.assign (i, j, rhs); + } + break; + } + + default: + error ("sparse indexing needs 1 or 2 indices"); + } + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (len, k+1); + throw; } @@ -212,35 +245,51 @@ { octave_idx_type len = idx.length (); - switch (len) - { - case 1: - { - idx_vector i = idx (0).index_vector (); + // If we catch an indexing error in index_vector, we flag an error in + // index k. Ensure it is the right value befor each idx_vector call. + // Same variable as used in the for loop in the default case. - if (! error_state) - matrix.delete_elements (i); + octave_idx_type k = 0; - break; - } - - case 2: - { - idx_vector i = idx (0).index_vector (); - - if (! error_state) + try + { + switch (len) + { + case 1: { - idx_vector j = idx (1).index_vector (); + idx_vector i = idx (0).index_vector (); if (! error_state) - matrix.delete_elements (i, j); + matrix.delete_elements (i); + + break; } - break; - } + case 2: + { + idx_vector i = idx (0).index_vector (); + + if (! error_state) + { + k = 1; + idx_vector j = idx (1).index_vector (); + + if (! error_state) + matrix.delete_elements (i, j); + } - default: - error ("sparse indexing needs 1 or 2 indices"); + break; + } + + default: + error ("sparse indexing needs 1 or 2 indices"); + } + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (len, k+1); + throw; } // Invalidate the matrix type
--- a/libinterp/octave-value/ov-base.cc +++ b/libinterp/octave-value/ov-base.cc @@ -218,8 +218,8 @@ idx_vector octave_base_value::index_vector (bool /* require_integers */) const { - std::string nm = type_name (); - error ("%s type invalid as index value", nm.c_str ()); + std::string nm = "<" + type_name () + ">"; + gripe_invalid_index (nm.c_str ()); return idx_vector (); }
--- a/libinterp/octave-value/ov-classdef.cc +++ b/libinterp/octave-value/ov-classdef.cc @@ -1647,7 +1647,16 @@ for (int i = 0; ! error_state && i < ival.length (); i++) { - iv(i) = ival(i).index_vector (); + try + { + iv(i) = ival(i).index_vector (); + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (ival.length (), i+1); + throw; + } if (! error_state) is_scalar = is_scalar && iv(i).is_scalar (); } @@ -1745,7 +1754,15 @@ for (int i = 0; ! error_state && i < ival.length (); i++) { - iv(i) = ival(i).index_vector (); + try + { + iv(i) = ival(i).index_vector (); + } + catch (index_exception& e) + { + e.set_pos_if_unset (ival.length (), i+1); + throw; // var name set in pt-idx.cc / pt-assign.cc + } if (! error_state) is_scalar = is_scalar && iv(i).is_scalar (); } @@ -1798,7 +1815,16 @@ for (int i = 0; ! error_state && i < ival.length (); i++) { - iv(i) = ival(i).index_vector (); + try + { + iv(i) = ival(i).index_vector (); + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (ival.length (), i+1); + throw; + } if (! error_state) {
--- a/libinterp/octave-value/ov-complex.cc +++ b/libinterp/octave-value/ov-complex.cc @@ -480,3 +480,39 @@ return octave_base_value::map (umap); } } + +class complex_index_exception : public index_exception +{ +public: + + complex_index_exception (const char *value) : index_exception (value) { } + + ~complex_index_exception (void) { } + + const char* explain (void) const + { + return "subscripts must be real (forgot to initialize i or j?)"; + } + + // ID of error to throw. + const char* id (void) const + { + return error_id_invalid_index; + } +}; + +// Complain if a complex value is used as a subscript + +void +gripe_complex_index (Complex idx) +{ + // FIXME: don't use a fixed size buffer! + + char buf [100]; + + sprintf (buf, "%g%+gi", std::real(idx), std::imag(idx)); + + complex_index_exception e (buf); + + throw e; +}
--- a/libinterp/octave-value/ov-complex.h +++ b/libinterp/octave-value/ov-complex.h @@ -43,6 +43,9 @@ class tree_walker; +extern void OCTAVE_API +gripe_complex_index (Complex idx); + // Complex scalar values. class @@ -81,8 +84,7 @@ // Use this to give a more specific error message idx_vector index_vector (bool /* require_integers */ = false) const { - error ("attempted to use a complex scalar as an index\n" - " (forgot to initialize i or j?)"); + gripe_complex_index (scalar); return idx_vector (); }
--- a/libinterp/octave-value/ov-java.cc +++ b/libinterp/octave-value/ov-java.cc @@ -827,28 +827,35 @@ jobjectArray retval = jni_env->NewObjectArray (idx.length (), ocls, 0); for (int i = 0; i < idx.length (); i++) - { - idx_vector v = idx(i).index_vector (); - - if (! error_state) - { - jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ())); - jint *buf = jni_env->GetIntArrayElements (i_array, 0); - - for (int k = 0; k < v.length (); k++) - buf[k] = v(k); - - jni_env->ReleaseIntArrayElements (i_array, buf, 0); - jni_env->SetObjectArrayElement (retval, i, i_array); - - check_exception (jni_env); - - if (error_state) - break; - } - else - break; - } + try + { + idx_vector v = idx(i).index_vector (); + + if (! error_state) + { + jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ())); + jint *buf = jni_env->GetIntArrayElements (i_array, 0); + + for (int k = 0; k < v.length (); k++) + buf[k] = v(k); + + jni_env->ReleaseIntArrayElements (i_array, buf, 0); + jni_env->SetObjectArrayElement (retval, i, i_array); + + check_exception (jni_env); + + if (error_state) + break; + } + else + break; + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (idx.length (), i+1); + throw; + } return retval; }
--- a/libinterp/octave-value/ov-perm.cc +++ b/libinterp/octave-value/ov-perm.cc @@ -74,8 +74,19 @@ idx_vector idx0, idx1; if (nidx == 2) { - idx0 = idx(0).index_vector (); - idx1 = idx(1).index_vector (); + int k = 0; // index we're processing when index_vector throws + try + { + idx0 = idx(0).index_vector (); + k = 1; + idx1 = idx(1).index_vector (); + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (2, k+1); + throw; + } } // This hack is to allow constructing permutation matrices using
--- a/libinterp/octave-value/ov-range.cc +++ b/libinterp/octave-value/ov-range.cc @@ -128,13 +128,25 @@ octave_value retval; // The range can handle a single subscript. - idx_vector i = idx(0).index_vector (); - if (! error_state) + + try { - if (i.is_scalar () && i(0) < range.numel ()) - retval = range.elem (i(0)); - else - retval = range.index (i); + idx_vector i = idx(0).index_vector (); + + if (! error_state) + { + if (i.is_scalar () && i(0) < range.numel ()) + retval = range.elem (i(0)); + else + retval = range.index (i); + } + } + catch (index_exception& e) + { + // More info may be added later before displaying error. + + e.set_pos_if_unset (1, 1); + throw; } return retval;
--- a/libinterp/octave-value/ov-re-diag.cc +++ b/libinterp/octave-value/ov-re-diag.cc @@ -92,31 +92,42 @@ // vectors. if (! resize_ok && idx.length () == 2 && matrix.is_multiple_of_identity (1)) { - idx_vector idx0 = idx(0).index_vector (); - idx_vector idx1 = idx(1).index_vector (); - - if (! error_state) + int k = 0; // index we're accesing when index_vector throws + try { - bool left = idx0.is_permutation (matrix.rows ()); - bool right = idx1.is_permutation (matrix.cols ()); + idx_vector idx0 = idx(0).index_vector (); + k = 1; + idx_vector idx1 = idx(1).index_vector (); - if (left && right) + if (! error_state) { - if (idx0.is_colon ()) left = false; - if (idx1.is_colon ()) right = false; + bool left = idx0.is_permutation (matrix.rows ()); + bool right = idx1.is_permutation (matrix.cols ()); + if (left && right) - retval = PermMatrix (idx0, false) * PermMatrix (idx1, true); - else if (left) - retval = PermMatrix (idx0, false); - else if (right) - retval = PermMatrix (idx1, true); - else { - retval = this; - this->count++; + if (idx0.is_colon ()) left = false; + if (idx1.is_colon ()) right = false; + if (left && right) + retval = PermMatrix (idx0, false) * PermMatrix (idx1, true); + else if (left) + retval = PermMatrix (idx0, false); + else if (right) + retval = PermMatrix (idx1, true); + else + { + retval = this; + this->count++; + } } } } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (2, k+1); + throw; + } } // if error_state is set, we've already griped.
--- a/libinterp/octave-value/ov-re-sparse.cc +++ b/libinterp/octave-value/ov-re-sparse.cc @@ -61,8 +61,8 @@ return idx_vector (array_value ()); else { - std::string nm = type_name (); - error ("%s type invalid as index value", nm.c_str ()); + std::string nm = "<" + type_name () + ">"; + gripe_invalid_index (nm.c_str ()); return idx_vector (); } }
--- a/libinterp/octave-value/ov-str-mat.cc +++ b/libinterp/octave-value/ov-str-mat.cc @@ -94,46 +94,62 @@ octave_idx_type len = idx.length (); - switch (len) - { - case 0: - retval = octave_value (matrix, type); - break; + // If we catch an indexing error in index_vector, we flag an error in + // index k. Ensure it is the right value befor each idx_vector call. + // Same variable as used in the for loop in the default case. + + octave_idx_type k = 0; - case 1: - { - idx_vector i = idx (0).index_vector (); + try + { + switch (len) + { + case 0: + retval = octave_value (matrix, type); + break; - if (! error_state) - retval = octave_value (charNDArray (matrix.index (i, resize_ok)), - type); - } - break; + case 1: + { + idx_vector i = idx (0).index_vector (); + + if (! error_state) + retval = octave_value (charNDArray (matrix.index (i, resize_ok)), + type); + } + break; - case 2: - { - idx_vector i = idx (0).index_vector (); - idx_vector j = idx (1).index_vector (); + case 2: + { + idx_vector i = idx (0).index_vector (); + k = 1; + idx_vector j = idx (1).index_vector (); - if (! error_state) - retval = octave_value (charNDArray (matrix.index (i, j, resize_ok)), - type); - } - break; + if (! error_state) + retval = octave_value (charNDArray (matrix.index (i, j, resize_ok)), + type); + } + break; + + default: + { + Array<idx_vector> idx_vec (dim_vector (len, 1)); - default: - { - Array<idx_vector> idx_vec (dim_vector (len, 1)); - - for (octave_idx_type i = 0; i < len; i++) - idx_vec(i) = idx(i).index_vector (); + for (k = 0; k < len; k++) + idx_vec(k) = idx(k).index_vector (); - if (! error_state) - retval = - octave_value (charNDArray (matrix.index (idx_vec, resize_ok)), - type); - } - break; + if (! error_state) + retval = + octave_value (charNDArray (matrix.index (idx_vec, resize_ok)), + type); + } + break; + } + } + catch (index_exception& e) + { + // Rethrow to allow more info to be reported later. + e.set_pos_if_unset (len, k+1); + throw; } return retval;
--- a/libinterp/parse-tree/pt-assign.cc +++ b/libinterp/parse-tree/pt-assign.cc @@ -106,41 +106,49 @@ } } - octave_lvalue ult = lhs->lvalue (); + try + { + octave_lvalue ult = lhs->lvalue (); - if (ult.numel () != 1) - gripe_nonbraced_cs_list_assignment (); - - if (! error_state) - { - ult.assign (etype, rhs_val); + if (ult.numel () != 1) + gripe_nonbraced_cs_list_assignment (); if (! error_state) { - if (etype == octave_value::op_asn_eq) - retval = rhs_val; - else - retval = ult.value (); + ult.assign (etype, rhs_val); - if (print_result () - && tree_evaluator::statement_printing_enabled ()) + if (! error_state) { - // We clear any index here so that we can - // get the new value of the referenced - // object below, instead of the indexed - // value (which should be the same as the - // right hand side value). + if (etype == octave_value::op_asn_eq) + retval = rhs_val; + else + retval = ult.value (); - ult.clear_index (); - - octave_value lhs_val = ult.value (); + if (print_result () + && tree_evaluator::statement_printing_enabled ()) + { + // We clear any index here so that we can + // get the new value of the referenced + // object below, instead of the indexed + // value (which should be the same as the + // right hand side value). - if (! error_state) - lhs_val.print_with_name (octave_stdout, - lhs->name ()); + ult.clear_index (); + + octave_value lhs_val = ult.value (); + + if (! error_state) + lhs_val.print_with_name (octave_stdout, + lhs->name ()); + } } } } + catch (index_exception& e) + { // problems with range, invalid index type etc. + e.set_var (lhs->name ()); + (*current_liboctave_error_with_id_handler) (e.id(), e.err()); + } } } }
--- a/libinterp/parse-tree/pt-id.h +++ b/libinterp/parse-tree/pt-id.h @@ -66,7 +66,7 @@ bool is_defined (void) { return sym->is_defined (); } - virtual bool is_variable (void) { return sym->is_variable (); } + virtual bool is_variable (void) const { return sym->is_variable (); } virtual bool is_black_hole (void) { return false; } @@ -152,7 +152,7 @@ std::string name (void) const { return "~"; } - bool is_variable (void) { return false; } + bool is_variable (void) const { return false; } bool is_black_hole (void) { return true; }
--- a/libinterp/parse-tree/pt-idx.cc +++ b/libinterp/parse-tree/pt-idx.cc @@ -284,6 +284,20 @@ return tree_index_expression::rvalue (nargout, 0); } +// Final step of processing an indexing error. Add the name of the +// variable being indexed, if any, then issue an error. (Will this also +// be needed by pt-lvalue, which calls subsref?) + +static void +final_index_error (index_exception& e, const tree_expression *expr) +{ + if (expr->is_identifier () + && dynamic_cast<const tree_identifier *> (expr)->is_variable ()) + e.set_var (expr->name ()); + + (*current_liboctave_error_with_id_handler) (e.id (), e.err ()); +} + octave_value_list tree_index_expression::rvalue (int nargout, const std::list<octave_lvalue> *lvalue_list) @@ -353,7 +367,7 @@ if (force_split || (al && al->has_magic_end ())) { - // We have an expression like + // (we have force_split, or) we have an expression like // // x{end}.a(end) // @@ -363,38 +377,45 @@ // that argument list so we can pass the appropriate // value to the built-in end function. - octave_value_list tmp_list - = tmp.subsref (type.substr (tmpi, i - tmpi), idx, nargout); - - tmp = tmp_list.length () ? tmp_list(0) : octave_value (); - tmpi = i; - idx.clear (); - - if (tmp.is_cs_list ()) - gripe_indexed_cs_list (); - - if (error_state) - break; - - if (tmp.is_function ()) + try { - octave_function *fcn = tmp.function_value (true); + octave_value_list tmp_list + =tmp.subsref (type.substr (tmpi, i-tmpi), idx, nargout); + + tmp = tmp_list.length () ? tmp_list(0) : octave_value (); + tmpi = i; + idx.clear (); - if (fcn && ! fcn->is_postfix_index_handled (type[i])) + if (tmp.is_cs_list ()) + gripe_indexed_cs_list (); + + if (error_state) + break; + + if (tmp.is_function ()) { - octave_value_list empty_args; + octave_function *fcn = tmp.function_value (true); - tmp_list = tmp.do_multi_index_op (1, empty_args); - tmp = (tmp_list.length () - ? tmp_list(0) : octave_value ()); + if (fcn && ! fcn->is_postfix_index_handled (type[i])) + { + octave_value_list empty_args; + + tmp_list = tmp.do_multi_index_op (1, empty_args); + tmp = (tmp_list.length () + ? tmp_list(0) : octave_value ()); - if (tmp.is_cs_list ()) - gripe_indexed_cs_list (); + if (tmp.is_cs_list ()) + gripe_indexed_cs_list (); - if (error_state) - break; + if (error_state) + break; + } } } + catch (index_exception& e) // problems with index range, type etc. + { + final_index_error (e, expr); + } } } @@ -433,8 +454,15 @@ if (! error_state) { - retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout, - lvalue_list); + try + { + retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout, + lvalue_list); + } + catch (index_exception& e) // problems with range, invalid index type etc. + { + final_index_error (e, expr); + } octave_value val = retval.length () ? retval(0) : octave_value (); @@ -500,7 +528,14 @@ gripe_indexed_cs_list (); else if (tmpi < i) { - tmp = tmp.subsref (type.substr (tmpi, i - tmpi), tmpidx, true); + try + { + tmp = tmp.subsref (type.substr (tmpi, i-tmpi), tmpidx, true); + } + catch (index_exception& e) // problems with range, invalid type etc. + { + final_index_error (e, expr); + } tmpidx.clear (); }
--- a/liboctave/array/Array-util.cc +++ b/liboctave/array/Array-util.cc @@ -178,9 +178,9 @@ compute_index (octave_idx_type n, const dim_vector& dims) { if (n < 0) - gripe_invalid_index (); + gripe_invalid_index (n, 1, 1); if (n >= dims.numel ()) - gripe_index_out_of_range (1, 1, n+1, dims.numel ()); + gripe_index_out_of_range (1, 1, n+1, dims.numel (), dims); return n; } @@ -188,12 +188,14 @@ octave_idx_type compute_index (octave_idx_type i, octave_idx_type j, const dim_vector& dims) { - if (i < 0 || j < 0) - gripe_invalid_index (); + if (i < 0) + gripe_invalid_index (i, 2, 1); + else if (j < 0) + gripe_invalid_index (j, 2, 2); if (i >= dims(0)) - gripe_index_out_of_range (2, 1, i+1, dims(0)); + gripe_index_out_of_range (2, 1, i+1, dims(0), dims); if (j >= dims.numel (1)) - gripe_index_out_of_range (2, 2, j+1, dims.numel (1)); + gripe_index_out_of_range (2, 2, j+1, dims.numel (1), dims); return j*dims(0) + i; } @@ -202,14 +204,18 @@ compute_index (octave_idx_type i, octave_idx_type j, octave_idx_type k, const dim_vector& dims) { - if (i < 0 || j < 0 || k < 0) - gripe_invalid_index (); + if (i < 0) + gripe_invalid_index (i, 3, 1); + else if (j < 0) + gripe_invalid_index (j, 3, 2); + else if (k < 0) + gripe_invalid_index (k, 3, 3); if (i >= dims(0)) - gripe_index_out_of_range (3, 1, i+1, dims(0)); + gripe_index_out_of_range (3, 1, i+1, dims(0), dims); if (j >= dims(1)) - gripe_index_out_of_range (3, 2, j+1, dims(1)); + gripe_index_out_of_range (3, 2, j+1, dims(1), dims); if (k >= dims.numel (2)) - gripe_index_out_of_range (3, 3, k+1, dims.numel (2)); + gripe_index_out_of_range (3, 3, k+1, dims.numel (2), dims); return (k*dims(1) + j)*dims(0) + i; } @@ -222,9 +228,9 @@ for (int d = 0; d < nd; d++) { if (ra_idx(d) < 0) - gripe_invalid_index (); + gripe_invalid_index (ra_idx(d), nd, d+1); if (ra_idx(d) >= dv(d)) - gripe_index_out_of_range (nd, d+1, ra_idx(d)+1, dv(d)); + gripe_index_out_of_range (nd, d+1, ra_idx(d)+1, dv(d), dims); } return dv.compute_index (ra_idx.data ()); @@ -540,18 +546,29 @@ for (octave_idx_type i = 0; i < len; i++) { - idx_vector idx = idxa(i); - octave_idx_type n = dvx(i); + try + { + idx_vector idx = idxa(i); + octave_idx_type n = dvx(i); + + all_ranges = all_ranges && idx.is_range (); + if (clen < 0) + clen = idx.length (n); + else if (clen != idx.length (n)) + current_liboctave_error_handler ("sub2ind: lengths of indices must match"); - all_ranges = all_ranges && idx.is_range (); - if (clen < 0) - clen = idx.length (n); - else if (clen != idx.length (n)) - current_liboctave_error_handler ("sub2ind: lengths of indices must match"); + if (idx.extent (n) > n) + gripe_index_out_of_range (len, i+1, idx.extent (n), n); + } + catch (index_exception& e) + { + e.set_pos_if_unset (len, i+1); + e.set_var (""); // no particular variable + (*current_liboctave_error_with_id_handler) (e.id(), e.err()); + } + } + // idxa known to be valid. Shouldn't need to catch index_exception below here. - if (idx.extent (n) > n) - current_liboctave_error_handler ("sub2ind: index out of range"); - } if (len == 1) retval = idxa(0);
--- a/liboctave/array/Array.cc +++ b/liboctave/array/Array.cc @@ -190,9 +190,9 @@ { // Do checks directly to avoid recomputing slice_len. if (n < 0) - gripe_invalid_index (); + gripe_invalid_index (n); if (n >= slice_len) - gripe_index_out_of_range (1, 1, n+1, slice_len); + gripe_index_out_of_range (1, 1, n+1, slice_len, dimensions); return elem (n); } @@ -224,9 +224,9 @@ { // Do checks directly to avoid recomputing slice_len. if (n < 0) - gripe_invalid_index (); + gripe_invalid_index (n); if (n >= slice_len) - gripe_index_out_of_range (1, 1, n+1, slice_len); + gripe_index_out_of_range (1, 1, n+1, slice_len, dimensions); return elem (n); } @@ -260,7 +260,7 @@ octave_idx_type r = dimensions(0); #ifdef BOUNDS_CHECKING if (k < 0 || k > dimensions.numel (1)) - gripe_index_out_of_range (2, 2, k+1, dimensions.numel (1)); + gripe_index_out_of_range (2, 2, k+1, dimensions.numel (1), dimensions); #endif return Array<T> (*this, dim_vector (r, 1), k*r, k*r + r); @@ -275,7 +275,7 @@ octave_idx_type p = r*c; #ifdef BOUNDS_CHECKING if (k < 0 || k > dimensions.numel (2)) - gripe_index_out_of_range (3, 3, k+1, dimensions.numel (2)); + gripe_index_out_of_range (3, 3, k+1, dimensions.numel (2), dimensions); #endif return Array<T> (*this, dim_vector (r, c), k*p, k*p + p); @@ -287,9 +287,9 @@ { #ifdef BOUNDS_CHECKING if (lo < 0) - gripe_index_out_of_range (1, 1, lo+1, numel ()); + gripe_index_out_of_range (1, 1, lo+1, numel (), dimensions); if (up > numel ()) - gripe_index_out_of_range (1, 1, up, numel ()); + gripe_index_out_of_range (1, 1, up, numel (), dimensions); #endif if (up < lo) up = lo; return Array<T> (*this, dim_vector (up - lo, 1), lo, up); @@ -726,7 +726,7 @@ else { if (i.extent (n) != n) - gripe_index_out_of_range (1, 1, i.extent (n), n); // throws + gripe_index_out_of_range (1, 1, i.extent (n), n, dimensions); // throws // FIXME: this is the only place where orig_dimensions are used. dim_vector rd = i.orig_dimensions (); @@ -793,9 +793,9 @@ else { if (i.extent (r) != r) - gripe_index_out_of_range (2, 1, i.extent (r), r); // throws + gripe_index_out_of_range (2, 1, i.extent (r), r, dimensions); // throws if (j.extent (c) != c) - gripe_index_out_of_range (2, 2, j.extent (c), c); // throws + gripe_index_out_of_range (2, 2, j.extent (c), c, dimensions); // throws octave_idx_type n = numel (); octave_idx_type il = i.length (r); @@ -855,7 +855,7 @@ for (int i = 0; i < ial; i++) { if (ia(i).extent (dv(i)) != dv(i)) - gripe_index_out_of_range (ial, i+1, ia(i).extent (dv(i)), dv(i)); // throws + gripe_index_out_of_range (ial, i+1, ia(i).extent (dv(i)), dv(i), dimensions); // throws all_colons = all_colons && ia(i).is_colon (); } @@ -1180,7 +1180,7 @@ } } else - gripe_invalid_assignment_size (); + gripe_nonconformant ("=", dim_vector(i.length(n),1), rhs.dims()); } // Assignment to a 2-dimensional array @@ -1284,7 +1284,7 @@ } // any empty RHS can be assigned to an empty LHS else if ((il != 0 && jl != 0) || (rhdv(0) != 0 && rhdv(1) != 0)) - gripe_assignment_dimension_mismatch (); + gripe_nonconformant ("=", il, jl, rhs.dim1 (), rhs.dim2 ()); } // Assignment to a multi-dimensional array @@ -1398,11 +1398,19 @@ rhsempty = rhsempty || (rhdv(j++) == 0); } if (! lhsempty || ! rhsempty) - gripe_assignment_dimension_mismatch (); + gripe_nonconformant ("=", dv, rhdv); } } } +/* +%!shared a +%! a = [1 2; 3 4]; +%!error <op1 is 1x2, op2 is 1x3> a(1,:) = [1 2 3] +%!error <op1 is 2x1, op2 is 1x3> a(:,1) = [1 2 3] +%!error <op1 is 2x2, op2 is 2x1> a(1:2,2:3) = [1;2] +*/ + template <class T> void Array<T>::delete_elements (const idx_vector& i)
--- a/liboctave/array/DiagArray2.cc +++ b/liboctave/array/DiagArray2.cc @@ -126,13 +126,13 @@ if (r < 0 || r >= dim1 ()) { - gripe_index_out_of_range (2, 1, r+1, dim1 ()); + gripe_index_out_of_range (2, 1, r+1, dim1 (), dims ()); ok = false; } if (c < 0 || c >= dim2 ()) { - gripe_index_out_of_range (2, 2, c+1, dim2 ()); + gripe_index_out_of_range (2, 2, c+1, dim2 (), dims ()); ok = false; }
--- a/liboctave/array/Sparse.cc +++ b/liboctave/array/Sparse.cc @@ -1431,7 +1431,7 @@ retval = tmp.index (idx); } else - gripe_index_out_of_range (1, 1, idx.extent (nel), nel); + gripe_index_out_of_range (1, 1, idx.extent (nel), nel, dims ()); } else if (nr == 1 && nc == 1) { @@ -1614,9 +1614,9 @@ retval = tmp.index (idx_i, idx_j); } else if (idx_i.extent (nr) > nr) - gripe_index_out_of_range (2, 1, idx_i.extent (nr), nr); + gripe_index_out_of_range (2, 1, idx_i.extent (nr), nr, dims ()); else - gripe_index_out_of_range (2, 2, idx_j.extent (nc), nc); + gripe_index_out_of_range (2, 2, idx_j.extent (nc), nc, dims ()); } else if (nr == 1 && nc == 1) { @@ -1978,7 +1978,7 @@ assign (idx, Sparse<T> (rhl, 1)); } else - gripe_invalid_assignment_size (); + gripe_nonconformant ("=", dim_vector(idx.length (n),1), rhs.dims()); } template <class T> @@ -2214,7 +2214,7 @@ assign (idx_i, idx_j, Sparse<T> (n, m)); } else - gripe_assignment_dimension_mismatch (); + gripe_nonconformant ("=", idx_i.length (nr), idx_j.length (nc), n, m); } // Can't use versions of these in Array.cc due to duplication of the
--- a/liboctave/array/idx-vector.cc +++ b/liboctave/array/idx-vector.cc @@ -113,9 +113,14 @@ gripe_invalid_range (); err = true; } - else if (start < 0 || (step < 0 && start + (len-1)*step < 0)) + else if (start < 0) { - gripe_invalid_index (); + gripe_invalid_index (start); + err = true; + } + else if (step < 0 && start + (len-1)*step < 0) + { + gripe_invalid_index (start + (len-1)*step); err = true; } } @@ -134,15 +139,23 @@ { start = static_cast<octave_idx_type> (r.base ()) - 1; step = static_cast<octave_idx_type> (r.inc ()); - if (start < 0 || (step < 0 && start + (len-1)*step < 0)) + if (start < 0) { - gripe_invalid_index (); + gripe_invalid_index (start); + err = true; + } + else if (step < 0 && start + (len-1)*step < 0) + { + gripe_invalid_index (start + (len-1)*step); err = true; } } else { - gripe_invalid_index (); + // find first non-integer, then gripe about it + double b = r.base(); + double inc = r.inc(); + gripe_invalid_index (b != floor(b) ? b : b+inc); err = true; } } @@ -221,7 +234,11 @@ octave_idx_type& ext) { if (i <= 0) - conv_error = true; + { + if (!conv_error) // only gripe once, for things like A(-10000:0) + gripe_invalid_index (i-1); + conv_error = true; + } if (ext < i) ext = i; @@ -235,7 +252,10 @@ octave_idx_type i = static_cast<octave_idx_type> (x); if (static_cast<double> (i) != x) - conv_error = true; + { + gripe_invalid_index (x-1); + conv_error = true; + } return convert_index (i, conv_error, ext); } @@ -264,9 +284,6 @@ octave_idx_type dummy = 0; data = convert_index (x, err, dummy); - - if (err) - gripe_invalid_index (); } idx_vector::idx_scalar_rep::idx_scalar_rep (octave_idx_type i) @@ -274,7 +291,7 @@ { if (data < 0) { - gripe_invalid_index (); + gripe_invalid_index (data); err = true; } } @@ -327,10 +344,7 @@ data = d; if (err) - { - delete [] data; - gripe_invalid_index (); - } + delete [] data; } } @@ -347,15 +361,16 @@ { octave_idx_type k = inda.xelem (i); if (k < 0) - err = true; + { + if (!err) // only report first error, in case 1000s. + gripe_invalid_index (k); + err = true; + } else if (k > max) max = k; } ext = max + 1; - - if (err) - gripe_invalid_index (); } } @@ -459,7 +474,7 @@ { if (n < 0 || n >= len) { - gripe_invalid_index (); + gripe_invalid_index (n); return 0; } @@ -709,7 +724,7 @@ { if (n < 0 || n >= len) { - gripe_invalid_index (); + gripe_invalid_index (n); return 0; }
--- a/liboctave/util/lo-array-gripes.cc +++ b/liboctave/util/lo-array-gripes.cc @@ -25,6 +25,7 @@ #include <config.h> #endif +#include <string.h> #include "lo-array-gripes.h" #include "lo-error.h" @@ -90,34 +91,6 @@ } void -gripe_index_out_of_range (int nd, int dim, octave_idx_type idx, - octave_idx_type ext) -{ - const char *err_id = error_id_index_out_of_bounds; - - switch (nd) - { - case 1: - (*current_liboctave_error_with_id_handler) - (err_id, "A(I): index out of bounds; value %d out of bound %d", - idx, ext); - break; - - case 2: - (*current_liboctave_error_with_id_handler) - (err_id, "A(I,J): %s index out of bounds; value %d out of bound %d", - (dim == 1) ? "row" : "column", idx, ext); - break; - - default: - (*current_liboctave_error_with_id_handler) - (err_id, "A(I,J,...): index to dimension %d out of bounds; value %d out of bound %d", - dim, idx, ext); - break; - } -} - -void gripe_del_index_out_of_range (bool is1d, octave_idx_type idx, octave_idx_type ext) { @@ -128,25 +101,234 @@ is1d ? "I" : "..,I,..", idx, ext); } -void -gripe_invalid_index (void) + + +// Common procedures of base class index_exception, thrown whenever an +// object is indexed incorrectly, such as by an index that is out of +// range, negative, fractional, complex, or of a non-numeric type. + +const char * +index_exception::err (void) throw () { - const char *err_id = error_id_invalid_index; + msg = access () + "; " + explain (); + return msg.c_str (); +} + +// Show what was illegally accessed, e.g., "A(-1,_)", "A(0+1i)", "A(_,3)" +// Show how many indices come before/after the offending one, +// e.g., (<error>), (<error>,_), or (_,<error>,...[x5]...) + +std::string +index_exception:: access (void) const +{ + // FIXME: don't use a fixed size buffer! + + int buf_len = 300; + + char output [buf_len]; + char pre [buf_len]; + char post [buf_len]; + + // dim == 0 if position not yet given, or + // <static_cast unsigned int>(-1) if explicitly shown to be unknown + // both are caught by this condition - (*current_liboctave_error_with_id_handler) -#ifdef USE_64_BIT_IDX_T - (err_id, "subscript indices must be either positive integers less than 2^63 or logicals"); -#else - (err_id, "subscript indices must be either positive integers less than 2^31 or logicals"); -#endif + if (static_cast <unsigned int> (dim-1) > 100000) + { + // No parentheses are given if the dimension is not known. + pre[0] = post[0] = '\0'; + } + else + { + if (dim < 5) + { + pre[0] = '('; + octave_idx_type i; + + for (i = 1; i < dim; i++) + { + pre[2*i-1] = '_'; + pre[2*i] = ','; + } + + pre[2*i-1] = '\0'; // i == min (1, dim) + } + else + { + sprintf (pre, "(...[x%d]...", dim-1); + } + + if (static_cast <unsigned int> (nd-dim) < 5) + { + for (octave_idx_type i = 0; i < nd-dim; i++) + { + post[2*i] = ','; + post[2*i+1] = '_'; + } + + if (nd >= dim) + { + post[2*(nd-dim)] = ')'; + post[2*(nd-dim)+1] = '\0'; + } + } + else + sprintf (post, "...[x%d]...)", nd-dim); + } + + const char *v; + + if (var[0] == '\0' || var == "<unknown>") + v = "index "; + else + v = var.c_str (); + + snprintf (output, buf_len, "%s%s%s%s", v, pre, idx(), post); + + return output; } -// FIXME: the following is a common error message to resize, -// regardless of whether it's called from assign or elsewhere. It -// seems OK to me, but eventually the gripe can be specialized. -// Anyway, propagating various error messages into procedure is, IMHO, -// a nonsense. If anything, we should change error handling here (and -// throughout liboctave) to allow custom handling of errors +class invalid_index : public index_exception +{ +public: + + invalid_index (const char *value, octave_idx_type ndim, + octave_idx_type dimen) + : index_exception (value, ndim, dimen) + { } + + const char* explain (void) const + { +#ifdef USE_64_BIT_IDX_T + return "subscripts must be either integers 1 to (2^63)-1 or logicals"; +#else + return "subscripts must be either integers 1 to (2^31)-1 or logicals"; +#endif + } + + // ID of error to throw + const char* id (void) const + { + return error_id_invalid_index; + } +}; + +// Complain of an index that is: negative, fractional, or too big. + +void +gripe_invalid_index (const char *idx, octave_idx_type nd, + octave_idx_type dim, const char * /* var */) +{ + invalid_index e (idx, nd, dim); + + throw e; +} + +void +gripe_invalid_index (octave_idx_type n, octave_idx_type nd, + octave_idx_type dim, const char *var) +{ + // FIXME: don't use a fixed size buffer! + char buf [100]; + + sprintf (buf, "%d", n+1); + + gripe_invalid_index (buf, nd, dim, var); +} + +void +gripe_invalid_index (double n, octave_idx_type nd, octave_idx_type dim, + const char *var) +{ + // FIXME: don't use a fixed size buffer! + char buf [100]; + + sprintf (buf, "%g", n+1); + + gripe_invalid_index (buf, nd, dim, var); +} + + +// Gripe and exception for read access beyond the bounds of an array. + +class out_of_range : public index_exception +{ +public: + + out_of_range (const char *value, octave_idx_type nd_in,octave_idx_type dim_in) + : index_exception (value, nd_in, dim_in), extent(0) + { } + + const char* explain (void) const + { + static std::string expl; // should probably be member variable, but + // then explain() can't be const. + + if (nd >= size.length ()) // if not an index slice + { + if (var != "") + expl = "but " + var + " has size "; + else + expl = "but object has size "; + + expl = expl + size.str ('x'); + } + else + { + // FIXME: don't use a fixed size buffer! + char buf [100]; + sprintf (buf, "%d", extent); + expl = "out of bound " + std::string (buf); + } + + return expl.c_str (); + } + + // ID of error to throw. + const char* id (void) const + { + return (error_id_index_out_of_bounds); + } + + void set_size (const dim_vector& size_in) { size = size_in; } + + void set_extent (octave_idx_type ext) { extent = ext; } + +private: + + dim_vector size; // dimension of object being accessed + + octave_idx_type extent; // length of dimension being accessed +}; + +// Complain of an index that is out of range, but we don't know matrix size +void +gripe_index_out_of_range (int nd, int dim, octave_idx_type idx, + octave_idx_type ext) +{ + char buf [100]; + sprintf (buf, "%d", idx); + out_of_range e (buf, nd, dim); + + e.set_extent (ext); + dim_vector d (1,1,1,1,1,1,1); // make explain() give extent not size + e.set_size (d); + throw e; +} + +// Complain of an index that is out of range +void +gripe_index_out_of_range (int nd, int dim, octave_idx_type idx, + octave_idx_type ext, const dim_vector& d) +{ + char buf [100]; + sprintf (buf, "%d", idx); + out_of_range e (buf, nd, dim); + + e.set_extent (ext); + e.set_size (d); + throw e; +} void gripe_invalid_resize (void) @@ -157,20 +339,6 @@ } void -gripe_invalid_assignment_size (void) -{ - (*current_liboctave_error_handler) - ("A(I) = X: X must have the same size as I"); -} - -void -gripe_assignment_dimension_mismatch (void) -{ - (*current_liboctave_error_handler) - ("A(I,J,...) = X: dimensions mismatch"); -} - -void gripe_singular_matrix (double rcond) { if (rcond == 0.0) @@ -186,3 +354,5 @@ "matrix singular to machine precision, rcond = %g", rcond); } } + +/* Tests in test/index.tst */
--- a/liboctave/util/lo-array-gripes.h +++ b/liboctave/util/lo-array-gripes.h @@ -24,6 +24,80 @@ #define octave_lo_array_gripes_h 1 #include "dim-vector.h" +#include "quit.h" + +// Exception thrown by gripe_invalid_index +// This is thrown when the invalid index is detected, at which point nd and dim +// are usually not known. It is caught at the place they are known, where a +// new gripe_invalid_index is called. +// +// Typically, this should be caught after any call to +// octave_value_list::index_vector() +class index_exception : public octave_execution_exception +{ +public: + + index_exception (const char *index_in, octave_idx_type nd_in = 0, + octave_idx_type dim_in = 0, const char *var_in = "") + : index (index_in), nd (nd_in), dim (dim_in), var (var_in) + { } + + ~index_exception (void) throw () { } + + // Erroneous index value. Called in what, and by external code + // (e.g., nth_element) to make a custom error message. + const char *idx (void) const { return index.c_str (); } + + // details set by subclass. + virtual const char* explain (void) const = 0; + + // ID of error to throw. + virtual const char* id (void) const = 0; + + virtual const char* err (void) throw (); + + // Position of error: dimension in error, and number of dimensions. + void set_pos (octave_idx_type nd_in, octave_idx_type dim_in) + { + nd = nd_in; + dim = dim_in; + } + + void set_pos_if_unset (octave_idx_type nd_in, octave_idx_type dim_in) + { + if (nd == 0) + { + nd = nd_in; + dim = dim_in; + } + } + + // Name of variable being indexed. eye(2)(1,1) gives "<unknown>". + void set_var (std::string var_in) { var = var_in; } + +private: + + // Value of invalid index. + std::string index; + + // Formatted message returned by what(), (not on stack). + std::string msg; + +protected: + + // Show what's wrong, e.g., A(-1,_), A(0+1i). + std::string access (void) const; + + // Number of dimensions of indexed object. + octave_idx_type nd; + + // Dimension number in which invalid index occurred. + octave_idx_type dim; + + // Name of variable being indexed. + std::string var; + +}; extern OCTAVE_API const char *error_id_nonconformant_args; @@ -57,6 +131,11 @@ extern void OCTAVE_API gripe_index_out_of_range (int nd, int dim, + octave_idx_type iext, octave_idx_type ext, + const dim_vector& d); + +extern void OCTAVE_API +gripe_index_out_of_range (int nd, int dim, octave_idx_type iext, octave_idx_type ext); extern void OCTAVE_API @@ -64,18 +143,21 @@ octave_idx_type ext); extern void OCTAVE_API -gripe_invalid_index (void); +gripe_invalid_index (double, octave_idx_type nd=0, + octave_idx_type dim=0, const char *var = NULL); + +extern void OCTAVE_API +gripe_invalid_index (octave_idx_type n, octave_idx_type nd=0, + octave_idx_type dim=0, const char *var = NULL); + +extern void OCTAVE_API +gripe_invalid_index (const char *idx, octave_idx_type nd=0, + octave_idx_type dim=0, const char *var = NULL); extern void OCTAVE_API gripe_invalid_resize (void); extern void OCTAVE_API -gripe_invalid_assignment_size (void); - -extern void OCTAVE_API -gripe_assignment_dimension_mismatch (void); - -extern void OCTAVE_API gripe_singular_matrix (double rcond = 0.0); #endif
--- a/test/index.tst +++ b/test/index.tst @@ -205,12 +205,6 @@ %!error (a(1:2,1:2) = 1:4) -%!shared x -%! x = 1:5; -%!error <attempted to use a complex scalar as an index> x(i) -%!error <attempted to use a complex scalar as an index> x(j) -%!error <attempted to use a complex scalar as an index> x(1+i) - ## bug #38357 %!shared d, dd %! d = diag ([1, 2, 3]); @@ -501,3 +495,84 @@ %! x = ones (2, 2); %! x([], false, :) = []; %! assert (x, y); + + + ## Test indexing of unnamed constants +%!error <index \(0\); subscripts must be> 1(0) +%!error <index \(-1\); subscripts must be> 1(-1) +%!error <index \(_,0.5\); subscripts> {}(1,0.5) +%!error <index \(nan,_\); subscripts> 1(NaN,1) +%!error <index \(_,_,<cell....\[x8\]...\); subscripts> [](1,1,{},1,1,1,1,1,1,1,1) +%!error <index \(...\[x9\]...-1,_\); subscript> 1(1,1,1,1,1,1,1,1,1,-1,1) +%!error <index \(2\); out of bound 1> 1(2) +%!error <index \(1\); out of bound 0> [](1) +%!error <index \(_,1\); but object has size 5x0> zeros(5,0)(3,1) +%!error <index \(3,_\); but object has size 0x5> zeros(0,5)(3,1) +%!error <index \(-1\); subscripts> 1(1)(-1)(1) +%! +%!shared abc +%! abc = [1, 2]; +%! ## Test full matrices in variables +%!error <abc\(3\); out of bound 2> abc([false, true, true]) +%!error <abc\(-1\); subscripts> abc(-1)(1)(1) +%! ## xerror <index \(-1\); subscripts> abc(1)(-1)(1) ## why no 'xerror' test? + +%!shared abc +%! abc = [1 2; 3 4]; +%!error <abc\(5\); out of bound 4> abc(5) +%!error <abc\(_,3\); but abc has size 2x2> abc(2,3) +%!error <abc\(_,_,0.5\); subscripts> exp (abc(2,3,0.5)) + +%!shared abc +%! abc = [1 2; 3 4]; abc(1,1,2) = 1; +%!error <abc\(_,5\); out of bound 4> abc(2,5) +%!error <abc\(_,3,_\); but abc has size 2x2x2> abc(2,3,2) +%!error <A\(..,I,..\) = \[\]: .* value 3 out of bound 2> abc(3,:) = [] +%!error <A\(I\) = \[\]: .* value 50 out of bound 8> abc(3:50) = [] +%!error <a null assignment can only have one non-colon index> abc(3,5) = [] +%!error <=: nonconformant arguments \(op1 is 1x1, op2 is 1x5\)> abc(3,5) = 1:5 + +%! ## Test diagonal matrices, and access of function results +%!error <index \(_,_,5\); but object has size 3x3> eye(3)(2,3,5) +%!error <index \(-2,_\); subscripts> eye(4)(-2,3) + +%! ## Test cells +%!shared abc +%! abc = {1, 2; 3, 4}; +%!error <abc\(_,0.3,_\); subscripts> abc(2,0.3,5) +%!error <abc\(_,0.3,_\); subscripts> abc{2,0.3,5} +%!error <abc\(-2,_,_,_\); subscripts> abc{-2,1,1,1} +%!error <abc\(0,_,_,_\); subscripts> abc(0,1,1,1) = 1 + +%! ## Test permutation matrices +%!shared abc +%! abc = eye(3)([3 1 2],:); +%!error <abc\(nan\); subscripts> abc(NA) +%!error <abc\(_,_,_,inf,_\); subscripts> abc(1,1,1,Inf,1) + +%! ## Test sparse matrices +%!shared abc +%! abc = sparse(3,3); +%!error <abc\(-1\); subscripts> abc(-1) +%!error <abc\(-1\); subscripts> abc(-1) = 1 +%!error <abc\(-1,_\); subscripts> abc(-1,1) +%!error <abc\(-1,_\); subscripts> abc(-1,1) = 1 +%!error <sparse indexing needs 1 or 2 indices> abc(0,0,0,0) +%!error <abc\(4,_\); but abc has size 3x3> abc(4,1) + +%! ## Test ranges +%!shared abc +%! abc = 1:10; +%!error <abc\(-1\); subscripts> abc(-1) +%!error <abc\(-1,_\); subscripts> abc(-1,1) +%!error <abc\(4,_\); but abc has size 1x10> abc(4,1) + +%! ## Test complex +%!shared abc, z +%! abc = [1 2]; +%!error <abc\(0\+1i\); subscripts must be real> abc(i) +%! abc = [1 2; 3 4]; +%!error <abc\(1\+0i\); subscripts must be real> abc(complex(1)) +%!error <abc\(1\+0.5i,_\); subscripts must be real> abc(1+0.5*i,3) +%!error <abc\(_,0-2i\); subscripts must be real> abc(2,0-2*i) +