changeset 30723:08b08b7f05b2

Replace direct calls to C library assert() with Octave specialty functions in libinterp/ (bug #61753) Define 4 new inline functions in error.h (panic_if, panic_unless, error_if, error_unless) that call either assert() or Octave's own error() function. Replace calls to assert() in code that maintains state and for which no recovery on detection of a problem is possible with calls to panic_XXX. Replace calls to assert() in interpreter code which could simply return to the Octave prompt when a problem is detected with calls to error_XXX. * error.h (panic_if, panic_unless): New functions which eventually call can call assert(). panic_if (COND) calls assert if COND is true. panic_unless (COND) calls assert if COND is false. * error.h (error_if, error_unless): New functions which eventually call can call Octave's error() function. error_if (COND) calls assert if COND is true. error_unless (COND) calls assert if COND is false. * cellfun.cc, daspk.cc, dasrt.cc, dassl.cc, data.cc, dot.cc, error.cc, graphics.cc, kron.cc, mex.cc, oct-map.cc, oct-stream.cc, pr-output.cc, schur.cc, stack-frame.cc, typecast.cc, variables.cc, ov-base.cc, ov-class.cc, ov-fcn-handle.cc, ov-struct.cc, ov-usr-fcn.cc, ov.h, ovl.cc, ops.h, profiler.cc, pt-classdef.cc, pt-eval.cc, pt-idx.cc, pt-pr-code.cc, pt-tm-const.cc, token.cc: Replace direct calls to C library assert() with Octave specialty functions.
author Arun Giridhar <arungiridhar@gmail.com> and Rik <rik@octave.org>
date Mon, 07 Feb 2022 21:47:53 -0800
parents 25de51cb4123
children 53b125563b49
files libinterp/corefcn/cellfun.cc libinterp/corefcn/daspk.cc libinterp/corefcn/dasrt.cc libinterp/corefcn/dassl.cc libinterp/corefcn/data.cc libinterp/corefcn/dot.cc libinterp/corefcn/error.cc libinterp/corefcn/error.h libinterp/corefcn/graphics.cc libinterp/corefcn/kron.cc libinterp/corefcn/mex.cc libinterp/corefcn/oct-map.cc libinterp/corefcn/oct-stream.cc libinterp/corefcn/pr-output.cc libinterp/corefcn/schur.cc libinterp/corefcn/stack-frame.cc libinterp/corefcn/typecast.cc libinterp/corefcn/variables.cc libinterp/octave-value/ov-base.cc libinterp/octave-value/ov-class.cc libinterp/octave-value/ov-fcn-handle.cc libinterp/octave-value/ov-struct.cc libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov.h libinterp/octave-value/ovl.cc libinterp/operators/ops.h libinterp/parse-tree/profiler.cc libinterp/parse-tree/pt-classdef.cc libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-idx.cc libinterp/parse-tree/pt-pr-code.cc libinterp/parse-tree/pt-tm-const.cc libinterp/parse-tree/token.cc
diffstat 33 files changed, 141 insertions(+), 107 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/cellfun.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/cellfun.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -1990,8 +1990,8 @@
 do_mat2cell_2d (const Array2D& a, const Array<octave_idx_type> *d, int nd)
 {
   Cell retval;
-  assert (nd == 1 || nd == 2);
-  assert (a.ndims () == 2);
+  error_unless (nd == 1 || nd == 2);
+  error_unless (a.ndims () == 2);
 
   if (mat2cell_mismatch (a.dims (), d, nd))
     return retval;
@@ -2047,7 +2047,7 @@
 do_mat2cell_nd (const ArrayND& a, const Array<octave_idx_type> *d, int nd)
 {
   Cell retval;
-  assert (nd >= 1);
+  error_unless (nd >= 1);
 
   if (mat2cell_mismatch (a.dims (), d, nd))
     return retval;
@@ -2111,7 +2111,7 @@
 do_mat2cell (octave_value& a, const Array<octave_idx_type> *d, int nd)
 {
   Cell retval;
-  assert (nd >= 1);
+  error_unless (nd >= 1);
 
   if (mat2cell_mismatch (a.dims (), d, nd))
     return retval;
--- a/libinterp/corefcn/daspk.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/daspk.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -68,7 +68,7 @@
 {
   ColumnVector retval;
 
-  assert (x.numel () == xdot.numel ());
+  error_unless (x.numel () == xdot.numel ());
 
   octave_value_list args;
 
@@ -117,7 +117,7 @@
 {
   Matrix retval;
 
-  assert (x.numel () == xdot.numel ());
+  error_unless (x.numel () == xdot.numel ());
 
   octave_value_list args;
 
--- a/libinterp/corefcn/dasrt.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/dasrt.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -69,7 +69,7 @@
 {
   ColumnVector retval;
 
-  assert (x.numel () == xdot.numel ());
+  error_unless (x.numel () == xdot.numel ());
 
   octave_value_list args;
 
@@ -155,7 +155,7 @@
 {
   Matrix retval;
 
-  assert (x.numel () == xdot.numel ());
+  error_unless (x.numel () == xdot.numel ());
 
   octave_value_list args;
 
--- a/libinterp/corefcn/dassl.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/dassl.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -67,7 +67,7 @@
 {
   ColumnVector retval;
 
-  assert (x.numel () == xdot.numel ());
+  error_unless (x.numel () == xdot.numel ());
 
   octave_value_list args;
 
@@ -116,7 +116,7 @@
 {
   Matrix retval;
 
-  assert (x.numel () == xdot.numel ());
+  error_unless (x.numel () == xdot.numel ());
 
   octave_value_list args;
 
--- a/libinterp/corefcn/data.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/data.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -8054,7 +8054,7 @@
           idx_vector col1 (':'), col2 (':'), sl1 (1, k), sl2 (0, k-1);
           retval = SparseT (retval.index (col1, sl1))
                    - SparseT (retval.index (col2, sl2));
-          assert (retval.columns () == k-1);
+          error_unless (retval.columns () == k-1);
           order--;
           k--;
         }
@@ -8067,7 +8067,7 @@
           idx_vector col1 (':'), col2 (':'), sl1 (1, k), sl2 (0, k-1);
           retval = SparseT (retval.index (sl1, col1))
                    - SparseT (retval.index (sl2, col2));
-          assert (retval.rows () == k-1);
+          error_unless (retval.rows () == k-1);
           order--;
           k--;
         }
@@ -8247,7 +8247,8 @@
 {
   Array<T> retval;
 
-  assert (rep.ndims () == 2 && rep.rows () == 2);
+  if (rep.ndims () != 2 || rep.rows () != 2)
+    error ("repelems: R must be a 2-row, N-column matrix of integers");
 
   octave_idx_type n = rep.columns ();
   octave_idx_type l = 0;
--- a/libinterp/corefcn/dot.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/dot.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -37,12 +37,14 @@
 
 OCTAVE_NAMESPACE_BEGIN
 
+// FIXME: input 'y' is no longer necessary (2/5/2022).
+//        At some point it would be better to change all occurrences of
+//        get_red_dims to eliminate this input parameter.
 static void
-get_red_dims (const dim_vector& x, const dim_vector& y, int dim,
+get_red_dims (const dim_vector& x, const dim_vector& /* y */, int dim,
               dim_vector& z, F77_INT& m, F77_INT& n, F77_INT& k)
 {
   int nd = x.ndims ();
-  assert (nd == y.ndims ());
   z = dim_vector::alloc (nd);
   octave_idx_type tmp_m = 1;
   octave_idx_type tmp_n = 1;
--- a/libinterp/corefcn/error.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/error.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -657,7 +657,7 @@
 
     octave_idx_type nel = ident.numel ();
 
-    assert (nel != 0);
+    panic_if (nel == 0);
 
     bool found = false;
 
@@ -689,8 +689,7 @@
     // The warning state "all" is always supposed to remain in the list,
     // so we should always find a state, either explicitly or by using the
     // state for "all".
-
-    assert (found);
+    panic_unless (found);
 
     retval.assign ("identifier", id);
     retval.assign ("state", val);
--- a/libinterp/corefcn/error.h	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/error.h	Mon Feb 07 21:47:53 2022 -0800
@@ -410,9 +410,6 @@
 // not deprecated and eventually removed, does it make sense to also
 // define them inside the octave namespace?
 
-#define panic_impossible()                                              \
-  panic ("impossible state reached in file '%s' at line %d", __FILE__, __LINE__)
-
 extern OCTINTERP_API void
 vmessage (const char *name, const char *fmt, va_list args);
 
@@ -508,6 +505,46 @@
 OCTAVE_NORETURN
 extern OCTINTERP_API void panic (const char *fmt, ...);
 
+#define panic_impossible()                                              \
+  panic ("impossible state reached in file '%s' at line %d", __FILE__, __LINE__)
+
+OCTINTERP_API inline
+void panic_if (bool cond)
+{
+#ifndef NDEBUG
+  if (cond)
+    panic_impossible ();
+  else
+    return;
+#endif
+}
+
+OCTINTERP_API inline
+void panic_unless (bool cond)
+{
+  panic_if (! cond);
+}
+
+#define error_impossible()                                              \
+  error ("impossible state reached in file '%s' at line %d", __FILE__, __LINE__)
+
+OCTINTERP_API inline
+void error_if (bool cond)
+{
+#ifndef NDEBUG
+  if (cond)
+    error_impossible ();
+  else
+    return;
+#endif
+}
+
+OCTINTERP_API inline
+void error_unless (bool cond)
+{
+  error_if (! cond);
+}
+
 OCTAVE_NAMESPACE_BEGIN
 
 //! Helper function for print_usage defined in defun.cc.
--- a/libinterp/corefcn/graphics.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/graphics.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -5504,11 +5504,11 @@
   // FIXME: Should this have all properties in it?
   // Including ones we do don't implement?
 
-  // FIXME: This function is probably never called without mode == "reset"
-  //        Check that this is the case with an assert statement (1/6/2017).
+  // FIXME: This function is probably never called without mode == "reset".
+  //        Verify this is the case with error_unless() (1/6/2017).
   //        If there are reports of problems then figure out what code is
   //        calling it with the mode set to something else.
-  assert (mode == "reset");
+  error_unless (mode == "reset");
 
   Matrix tlim (1, 2, 0.0);
   tlim(1) = 1;
--- a/libinterp/corefcn/kron.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/kron.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -55,8 +55,8 @@
 static MArray<T>
 kron (const MArray<R>& a, const MArray<T>& b)
 {
-  assert (a.ndims () == 2);
-  assert (b.ndims () == 2);
+  error_unless (a.ndims () == 2);
+  error_unless (b.ndims () == 2);
 
   octave_idx_type nra = a.rows ();
   octave_idx_type nrb = b.rows ();
@@ -86,7 +86,7 @@
 static MArray<T>
 kron (const MDiagArray2<R>& a, const MArray<T>& b)
 {
-  assert (b.ndims () == 2);
+  error_unless (b.ndims () == 2);
 
   octave_idx_type nra = a.rows ();
   octave_idx_type nrb = b.rows ();
--- a/libinterp/corefcn/mex.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/mex.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -462,7 +462,7 @@
     mxArray *retval = m_val.as_mxArray (m_interleaved);
 
     // RETVAL is assumed to be an mxArray_matlab object.  Should we
-    // assert that condition here?
+    // error_unless that condition here?
 
     if (retval)
       {
--- a/libinterp/corefcn/oct-map.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/oct-map.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -498,8 +498,6 @@
 octave_map
 octave_map::transpose (void) const
 {
-  assert (ndims () == 2);
-
   octave_map retval (m_keys);
 
   retval.m_dimensions = dim_vector (m_dimensions (1), m_dimensions (0));
@@ -614,7 +612,7 @@
   for (octave_idx_type j = 0; j < nf; j++)
     {
       retval.m_vals.push_back (Cell (rd));
-      assert (retval.m_vals[j].numel () == n);
+      error_unless (retval.m_vals[j].numel () == n);
       for (octave_idx_type i = 0; i < n; i++)
         retval.m_vals[j].xelem (i) = map_list[i].m_vals[j];
     }
@@ -1033,7 +1031,7 @@
           error (ee, "incompatible fields in struct assignment");
         }
 
-      assert (rhs1.m_keys.is_same (m_keys));
+      error_unless (rhs1.m_keys.is_same (m_keys));
       assign (i, rhs1);
     }
 }
@@ -1081,7 +1079,7 @@
           error (ee, "incompatible fields in struct assignment");
         }
 
-      assert (rhs1.m_keys.is_same (m_keys));
+      error_unless (rhs1.m_keys.is_same (m_keys));
       assign (i, j, rhs1);
     }
 }
@@ -1129,7 +1127,7 @@
           error (ee, "incompatible fields in struct assignment");
         }
 
-      assert (rhs1.m_keys.is_same (m_keys));
+      error_unless (rhs1.m_keys.is_same (m_keys));
       assign (ia, rhs1);
     }
 }
--- a/libinterp/corefcn/oct-stream.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/oct-stream.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -6658,7 +6658,7 @@
     std::ptrdiff_t input_buf_size
       = static_cast<std::ptrdiff_t> (input_buf_elts) * input_elt_size;
 
-    assert (input_buf_size >= 0);
+    error_if (input_buf_size < 0);
 
     // Must also work and return correct type object for 0 elements to read.
     std::istream *isp = input_stream ();
--- a/libinterp/corefcn/pr-output.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/pr-output.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -300,7 +300,7 @@
 pr_max_internal (const MArray<T>& m)
 {
   // We expect a 2-d array.
-  assert (m.ndims () == 2);
+  error_unless (m.ndims () == 2);
 
   octave_idx_type nr = m.rows ();
   octave_idx_type nc = m.columns ();
@@ -680,7 +680,7 @@
 static inline float_display_format
 make_matrix_format (const MT& m)
 {
-  assert (m.ndims () == 2);
+  error_unless (m.ndims () == 2);
 
   if (free_format)
     return float_display_format ();
@@ -1570,7 +1570,7 @@
 print_empty_matrix (std::ostream& os, octave_idx_type nr, octave_idx_type nc,
                     bool pr_as_read_syntax)
 {
-  assert (nr == 0 || nc == 0);
+  error_unless (nr == 0 || nc == 0);
 
   if (pr_as_read_syntax)
     {
@@ -1592,7 +1592,7 @@
 print_empty_nd_array (std::ostream& os, const dim_vector& dims,
                       bool pr_as_read_syntax)
 {
-  assert (dims.any_zero ());
+  error_unless (dims.any_zero ());
 
   if (pr_as_read_syntax)
     os << "zeros (" << dims.str (',') << ')';
--- a/libinterp/corefcn/schur.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/schur.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -46,7 +46,7 @@
   octave_value retval = a;
 
   octave_idx_type n = a.rows ();
-  assert (a.columns () == n);
+  error_unless (a.columns () == n);
 
   const typename Matrix::element_type zero = typename Matrix::element_type ();
 
--- a/libinterp/corefcn/stack-frame.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/stack-frame.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -31,6 +31,7 @@
 #include "str-vec.h"
 
 #include "defun.h"
+#include "error.h"
 #include "interpreter.h"
 #include "interpreter-private.h"
 #include "oct-map.h"
@@ -1603,7 +1604,7 @@
     // scope.  If the symbol wasn't present before, it should be outside
     // the range so we need to resize then update offsets.
 
-    assert (data_offset >= size ());
+    panic_unless (data_offset >= size ());
 
     resize (data_offset+1);
 
@@ -1654,7 +1655,7 @@
 
     if (sym)
       {
-        assert (sym.frame_offset () == 0);
+        panic_unless (sym.frame_offset () == 0);
 
         return sym;
       }
@@ -1683,7 +1684,7 @@
         // All symbol records in a script scope should have zero offset,
         // which means we redirect our lookup using
         // lexical_frame_offsets and values_offets.
-        assert (sym.frame_offset () == 0);
+        panic_unless (sym.frame_offset () == 0);
 
         return sym;
       }
@@ -1693,7 +1694,7 @@
 
     sym = scope.find_symbol (name);
 
-    assert (sym);
+    panic_unless (sym.is_valid ());
 
     resize_and_update_script_offsets (sym);
 
@@ -2104,7 +2105,7 @@
           {
             // FIXME: do we need to ensure that the called
             // function is a child of the caller?  Does it hurt
-            // to assert this condition, at least for now?
+            // to panic_unless this condition, at least for now?
 
             alink = static_link;
           }
@@ -2112,7 +2113,7 @@
           {
             // FIXME: do we need to check that the parent of the
             // called function is also a parent of the caller?
-            // Does it hurt to assert this condition, at least
+            // Does it hurt to panic_unless this condition, at least
             // for now?
 
             int links_to_follow = caller_nesting_depth - nesting_depth + 1;
@@ -2225,7 +2226,7 @@
 
     sym = scope.find_symbol (name);
 
-    assert (sym);
+    panic_unless (sym.is_valid ());
 
     return sym;
   }
@@ -2392,7 +2393,7 @@
 
     sym = m_scope.find_symbol (name);
 
-    assert (sym);
+    panic_unless (sym.is_valid ());
 
     return sym;
   }
--- a/libinterp/corefcn/typecast.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/typecast.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -206,8 +206,6 @@
       else if (array.is_uint64_type ())
         get_data_and_bytesize (array.uint64_array_value (), data, byte_size,
                                old_dims, frame);
-      else
-        assert (0);
     }
   else if (array.iscomplex ())
     {
@@ -548,8 +546,6 @@
         retval = do_bitunpack (array.uint32_array_value ());
       else if (array.is_uint64_type ())
         retval = do_bitunpack (array.uint64_array_value ());
-      else
-        assert (0);
     }
   else if (array.iscomplex ())
     {
--- a/libinterp/corefcn/variables.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/corefcn/variables.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -772,7 +772,7 @@
 
   int nargin = args.length ();
 
-  assert (var < nchoices);
+  error_unless (var < nchoices);
 
   if (nargout > 0 || nargin == 0)
     retval = choices[var];
--- a/libinterp/octave-value/ov-base.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/octave-value/ov-base.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -1355,7 +1355,7 @@
 void
 octave_base_value::indent (std::ostream& os) const
 {
-  assert (s_curr_print_indent_level >= 0);
+  panic_unless (s_curr_print_indent_level >= 0);
 
   if (s_beginning_of_line)
     {
--- a/libinterp/octave-value/ov-class.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/octave-value/ov-class.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -281,7 +281,7 @@
 Cell
 octave_class::dotref (const octave_value_list& idx)
 {
-  assert (idx.length () == 1);
+  panic_if (idx.length () != 1);
 
   std::string method_class = get_current_method_class ();
 
@@ -654,7 +654,7 @@
 
                 octave_value_list key_idx = *++p;
 
-                assert (key_idx.length () == 1);
+                panic_if (key_idx.length () != 1);
 
                 std::string key = key_idx(0).xstring_value ("invalid index for class assignment");
 
@@ -692,7 +692,7 @@
           {
             octave_value_list key_idx = idx.front ();
 
-            assert (key_idx.length () == 1);
+            panic_if (key_idx.length () != 1);
 
             std::string key = key_idx(0).string_value ();
 
@@ -747,7 +747,7 @@
             auto p = idx.begin ();
             octave_value_list key_idx = *++p;
 
-            assert (key_idx.length () == 1);
+            panic_if (key_idx.length () != 1);
 
             std::string key = key_idx(0).xstring_value ("assignment to class element failed");
 
@@ -785,7 +785,7 @@
       {
         octave_value_list key_idx = idx.front ();
 
-        assert (key_idx.length () == 1);
+        panic_if (key_idx.length () != 1);
 
         std::string key = key_idx(0).string_value ();
 
@@ -1068,7 +1068,7 @@
           // Something has gone terribly wrong if
           // symbol_table::find_method (c_name, c_name) does not return
           // a class constructor for the class c_name...
-          assert (have_ctor);
+          panic_unless (have_ctor);
         }
 
       if (have_ctor)
--- a/libinterp/octave-value/ov-fcn-handle.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -2628,14 +2628,14 @@
 
     tree_statement_list *b = f->body ();
 
-    assert (b->length () == 1);
+    panic_if (b->length () != 1);
 
     tree_statement *s = b->front ();
 
     if (! s)
       error ("invalid anonymous function handle");
 
-    assert (s->is_expression ());
+    panic_unless (s->is_expression ());
 
     tree_expression *e = s->expression ();
 
--- a/libinterp/octave-value/ov-struct.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/octave-value/ov-struct.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -91,7 +91,7 @@
 {
   Cell retval;
 
-  assert (idx.length () == 1);
+  panic_if (idx.length () != 1);
 
   std::string nm = idx(0).string_value ();
 
@@ -321,7 +321,7 @@
 
                 octave_value_list key_idx = *++p;
 
-                assert (key_idx.length () == 1);
+                panic_if (key_idx.length () != 1);
 
                 std::string key = key_idx(0).string_value ();
 
@@ -377,7 +377,7 @@
           {
             octave_value_list key_idx = idx.front ();
 
-            assert (key_idx.length () == 1);
+            panic_if (key_idx.length () != 1);
 
             std::string key = key_idx(0).string_value ();
 
@@ -443,7 +443,7 @@
             octave_value_list key_idx = *++p;
             octave_value_list idxf = idx.front ();
 
-            assert (key_idx.length () == 1);
+            panic_if (key_idx.length () != 1);
 
             std::string key = key_idx(0).string_value ();
 
@@ -514,7 +514,7 @@
       {
         octave_value_list key_idx = idx.front ();
 
-        assert (key_idx.length () == 1);
+        panic_if (key_idx.length () != 1);
 
         std::string key = key_idx(0).string_value ();
 
@@ -1107,7 +1107,7 @@
 {
   octave_value retval;
 
-  assert (idx.length () == 1);
+  panic_if (idx.length () != 1);
 
   std::string nm = idx(0).string_value ();
 
@@ -1228,7 +1228,7 @@
 
       octave_value_list key_idx = idx.front ();
 
-      assert (key_idx.length () == 1);
+      panic_if (key_idx.length () != 1);
 
       std::string key = key_idx(0).string_value ();
 
@@ -2114,7 +2114,7 @@
   // result dimensions.
   dim_vector rdv = vals.dims ().redim (nd);
 
-  assert (ext == rdv(dim));
+  panic_unless (ext == rdv(dim));
   if (nd == 2)
     {
       rdv(0) = rdv(1-dim);
--- a/libinterp/octave-value/ov-usr-fcn.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -504,8 +504,8 @@
 octave::tree_expression *
 octave_user_function::special_expr (void)
 {
-  assert (is_special_expr ());
-  assert (m_cmd_list->length () == 1);
+  panic_unless (is_special_expr ());
+  panic_if (m_cmd_list->length () != 1);
 
   octave::tree_statement *stmt = m_cmd_list->front ();
   return stmt->expression ();
--- a/libinterp/octave-value/ov.h	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/octave-value/ov.h	Mon Feb 07 21:47:53 2022 -0800
@@ -1526,8 +1526,7 @@
 
   bool islocked (void) const { return m_rep->islocked (); }
 
-  void call_object_destructor (void)
-  { return m_rep->call_object_destructor (); }
+  void call_object_destructor (void) { return m_rep->call_object_destructor (); }
 
   octave_value dump (void) const { return m_rep->dump (); }
 
@@ -1873,6 +1872,8 @@
 extern OCTINTERP_API void install_types (octave::type_info&);
 
 // Templated value extractors.
+// FIXME: would be more consistent to use panic_impossible(), rather than
+//        assert(), but including "error.h" leads to compilation errors.
 template <typename Value>
 inline Value octave_value_extract (const octave_value&)
 { assert (false); }
--- a/libinterp/octave-value/ovl.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/octave-value/ovl.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -71,7 +71,7 @@
             m_data[k++] = ovl(i);
         }
 
-      assert (k == nel);
+      panic_unless (k == nel);
     }
 
 }
--- a/libinterp/operators/ops.h	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/operators/ops.h	Mon Feb 07 21:47:53 2022 -0800
@@ -29,6 +29,7 @@
 #include "octave-config.h"
 
 #include "Array-util.h"
+#include "error.h"
 
 namespace octave
 {
@@ -130,7 +131,7 @@
     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
-    assert (idx.empty ());                                              \
+    error_unless (idx.empty ());                                        \
     v1.matrix_ref () op v2.CONCAT2 (f, _value) ();                      \
                                                                         \
     return octave_value ();                                             \
@@ -145,7 +146,7 @@
     CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
-    assert (idx.empty ());                                              \
+    error_unless (idx.empty ());                                        \
     fnop (v1.matrix_ref (), v2.CONCAT2 (f, _value) ());                 \
                                                                         \
     return octave_value ();                                             \
--- a/libinterp/parse-tree/profiler.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/parse-tree/profiler.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -52,8 +52,6 @@
     for (const auto& nm : list)
       retval(i++) = nm;
 
-    assert (i == n);
-
     return retval;
   }
 
@@ -88,10 +86,10 @@
   profiler::tree_node*
   profiler::tree_node::exit (octave_idx_type /* fcn */)
   {
-    // FIXME: These assert statements don't make sense if profile() is called
-    //        from within a function hierarchy to begin with.  See bug #39587.
-    //  assert (m_parent);
-    //  assert (m_fcn_id == fcn);
+    // FIXME: These panic_unless statements don't make sense if profile() is
+    //  called from within a function hierarchy to begin with.  See bug #39587.
+    //  panic_unless (m_parent);
+    //  panic_unless (m_fcn_id == fcn);
 
     return m_parent;
   }
@@ -108,7 +106,7 @@
         entry.m_time += m_time;
         entry.m_calls += m_calls;
 
-        assert (m_parent);
+        panic_unless (m_parent);
         if (m_parent->m_fcn_id != 0)
           {
             entry.m_parents.insert (m_parent->m_fcn_id);
@@ -162,7 +160,6 @@
 
         ++i;
       }
-    assert (i == n);
 
     octave_map retval;
 
@@ -196,8 +193,8 @@
   profiler::enter_function (const std::string& fcn)
   {
     // The enter class will check and only call us if the profiler is active.
-    assert (enabled ());
-    assert (m_call_tree);
+    panic_unless (enabled ());
+    panic_unless (m_call_tree);
 
     // If there is already an active function, add to its time before
     // pushing the new one.
@@ -230,11 +227,11 @@
   {
     if (m_active_fcn)
       {
-        assert (m_call_tree);
-        // FIXME: This assert statements doesn't make sense if profile() is
-        // called from within a function hierarchy to begin with.  See bug
-        // #39587.
-        //assert (m_active_fcn != m_call_tree);
+        panic_unless (m_call_tree);
+        // FIXME: This panic_unless statements doesn't make sense if profile()
+        //        is called from within a function hierarchy to begin with.
+        //        See bug #39587.
+        // panic_unless (m_active_fcn != m_call_tree);
 
         // Usually, if we are disabled this function is not even called.  But
         // the call disabling the profiler is an exception.  So also check here
@@ -243,10 +240,10 @@
           add_current_time ();
 
         fcn_index_map::iterator pos = m_fcn_index.find (fcn);
-        // FIXME: This assert statements doesn't make sense if profile() is
-        // called from within a function hierarchy to begin with.  See bug
-        // #39587.
-        //assert (pos != m_fcn_index.end ());
+        // FIXME: This panic_unless statements doesn't make sense if profile()
+        //        is called from within a function hierarchy to begin with.
+        //        See bug #39587.
+        // panic_unless (pos != m_fcn_index.end ());
         m_active_fcn = m_active_fcn->exit (pos->second);
 
         // If this was an "inner call", we resume executing the parent function
--- a/libinterp/parse-tree/pt-classdef.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/parse-tree/pt-classdef.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -61,10 +61,9 @@
         // part of an index expression.  It is also not an identifier in
         // the syntax tree but we need to handle it as if it were.  So
         // call the function here.
-
         octave_function *f = tmp.function_value (true);
 
-        assert (f);
+        panic_unless (f);
 
         return f->call (tw, nargout);
       }
--- a/libinterp/parse-tree/pt-eval.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/parse-tree/pt-eval.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -3487,7 +3487,7 @@
 
         if (user_function.is_special_expr ())
           {
-            assert (cmd_list->length () == 1);
+            panic_if (cmd_list->length () != 1);
 
             tree_statement *stmt = cmd_list->front ();
 
--- a/libinterp/parse-tree/pt-idx.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/parse-tree/pt-idx.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -346,7 +346,7 @@
   {
     octave_value_list retval;
 
-    assert (! m_args.empty ());
+    panic_if (m_args.empty ());
 
     auto p_args = m_args.begin ();
     auto p_arg_nm = m_arg_nm.begin ();
--- a/libinterp/parse-tree/pt-pr-code.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/parse-tree/pt-pr-code.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -1203,7 +1203,7 @@
   void
   tree_print_code::indent (void)
   {
-    assert (m_curr_print_indent_level >= 0);
+    panic_unless (m_curr_print_indent_level >= 0);
 
     if (m_beginning_of_line)
       {
--- a/libinterp/parse-tree/pt-tm-const.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/parse-tree/pt-tm-const.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -608,7 +608,8 @@
           {
             // Optimize all scalars case.
             TYPE result (m_dv);
-            assert (static_cast<std::size_t> (result.numel ()) == row.length ());
+            panic_unless (static_cast<std::size_t> (result.numel ())
+                          == row.length ());
             octave_idx_type i = 0;
             for (const auto& elt : row)
               result(i++) = octave_value_extract<ELT_T> (elt);
--- a/libinterp/parse-tree/token.cc	Mon Feb 07 10:46:17 2022 +0900
+++ b/libinterp/parse-tree/token.cc	Mon Feb 07 21:47:53 2022 -0800
@@ -29,6 +29,7 @@
 
 #include <cassert>
 
+#include "error.h"
 #include "token.h"
 
 namespace octave
@@ -95,14 +96,14 @@
   std::string
   token::text (void) const
   {
-    assert (m_type_tag == string_token);
+    panic_if (m_type_tag != string_token);
     return *m_tok_info.m_str;
   }
 
   octave_value
   token::number (void) const
   {
-    assert (m_type_tag == numeric_token);
+    panic_if (m_type_tag != numeric_token);
     return *m_tok_info.m_num;
   }
 
@@ -115,21 +116,21 @@
   token::end_tok_type
   token::ettype (void) const
   {
-    assert (m_type_tag == ettype_token);
+    panic_if (m_type_tag != ettype_token);
     return m_tok_info.m_et;
   }
 
   std::string
   token::superclass_method_name (void) const
   {
-    assert (m_type_tag == scls_name_token);
+    panic_if (m_type_tag != scls_name_token);
     return m_tok_info.m_superclass_info->m_method_name;
   }
 
   std::string
   token::superclass_class_name (void) const
   {
-    assert (m_type_tag == scls_name_token);
+    panic_if (m_type_tag != scls_name_token);
     return m_tok_info.m_superclass_info->m_class_name;
   }