changeset 20574: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.
author Lachlan Andrew <lachlanbis@gmail.com>
date Fri, 02 Oct 2015 15:07:37 -0400
parents e3c0fee87493
children 3339c9bdfe6a
files libinterp/corefcn/Cell.cc libinterp/corefcn/data.cc libinterp/corefcn/find.cc libinterp/corefcn/oct-map.cc libinterp/corefcn/sparse.cc libinterp/corefcn/sub2ind.cc libinterp/corefcn/toplev.cc libinterp/corefcn/utils.cc libinterp/octave-value/ov-base-diag.cc libinterp/octave-value/ov-base-mat.cc libinterp/octave-value/ov-base-sparse.cc libinterp/octave-value/ov-base.cc libinterp/octave-value/ov-classdef.cc libinterp/octave-value/ov-complex.cc libinterp/octave-value/ov-complex.h libinterp/octave-value/ov-java.cc libinterp/octave-value/ov-perm.cc libinterp/octave-value/ov-range.cc libinterp/octave-value/ov-re-diag.cc libinterp/octave-value/ov-re-sparse.cc libinterp/octave-value/ov-str-mat.cc libinterp/parse-tree/pt-assign.cc libinterp/parse-tree/pt-id.h libinterp/parse-tree/pt-idx.cc liboctave/array/Array-util.cc liboctave/array/Array.cc liboctave/array/DiagArray2.cc liboctave/array/Sparse.cc liboctave/array/idx-vector.cc liboctave/util/lo-array-gripes.cc liboctave/util/lo-array-gripes.h test/index.tst
diffstat 32 files changed, 1598 insertions(+), 796 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/Cell.cc	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/corefcn/Cell.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/corefcn/data.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/corefcn/find.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/corefcn/oct-map.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/corefcn/sparse.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/corefcn/sub2ind.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/corefcn/toplev.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/corefcn/utils.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-base-diag.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-base-mat.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-base-sparse.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-base.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-classdef.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-complex.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-complex.h	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-java.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-perm.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-range.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-re-diag.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-re-sparse.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/octave-value/ov-str-mat.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/parse-tree/pt-assign.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/parse-tree/pt-id.h	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/libinterp/parse-tree/pt-idx.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/liboctave/array/Array-util.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/liboctave/array/Array.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/liboctave/array/DiagArray2.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/liboctave/array/Sparse.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/liboctave/array/idx-vector.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/liboctave/util/lo-array-gripes.cc	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/liboctave/util/lo-array-gripes.h	Fri Oct 02 15:07:37 2015 -0400
@@ -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	Fri Oct 02 12:25:39 2015 -0400
+++ b/test/index.tst	Fri Oct 02 15:07:37 2015 -0400
@@ -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)
+