changeset 33024:1220b63eea0e bytecode-interpreter

maint: Merge default to bytecode-interpreter
author Arun Giridhar <arungiridhar@gmail.com>
date Wed, 14 Feb 2024 18:52:17 -0500
parents 19973af3ac42 (current diff) 92a2e883af17 (diff)
children a71bde898ef9
files libinterp/parse-tree/pt-eval.cc
diffstat 13 files changed, 312 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.github/dependabot.yml	Wed Feb 14 18:52:17 2024 -0500
@@ -0,0 +1,10 @@
+# Set update schedule for GitHub Actions
+
+version: 2
+updates:
+
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      # Check for updates to GitHub Actions every week
+      interval: "weekly"
--- a/.github/workflows/codeql-analysis.yaml	Sun Feb 11 09:40:35 2024 -0500
+++ b/.github/workflows/codeql-analysis.yaml	Wed Feb 14 18:52:17 2024 -0500
@@ -51,7 +51,7 @@
 
       - name: initialize CodeQL
         # Initialize the CodeQL tools for scanning.
-        uses: github/codeql-action/init@v2
+        uses: github/codeql-action/init@v3
         with:
           languages: ${{ matrix.language }}
           # If you wish to specify custom queries, you can do so here or in a config file.
@@ -63,7 +63,7 @@
         run: make -C ./.build all -j2 V=1
 
       - name: perform CodeQL analysis
-        uses: github/codeql-action/analyze@v2
+        uses: github/codeql-action/analyze@v3
 
 
   windows:
@@ -171,7 +171,7 @@
 
       - name: initialize CodeQL
         # Initialize the CodeQL tools for scanning.
-        uses: github/codeql-action/init@v2
+        uses: github/codeql-action/init@v3
         with:
           languages: ${{ matrix.language }}
           # If you wish to specify custom queries, you can do so here or in a config file.
@@ -185,4 +185,4 @@
         run: make -C ./.build all -j8 V=1
 
       - name: perform CodeQL analysis
-        uses: github/codeql-action/analyze@v2
+        uses: github/codeql-action/analyze@v3
--- a/doc/interpreter/expr.txi	Sun Feb 11 09:40:35 2024 -0500
+++ b/doc/interpreter/expr.txi	Wed Feb 14 18:52:17 2024 -0500
@@ -1233,6 +1233,7 @@
 thing = "food"
 predicate = "good"
 message = [ "this " , thing , " is " , predicate ]
+@result{} "this food is good"
 @end group
 @end example
 
@@ -1264,9 +1265,9 @@
 
 @example
 @group
-octave:13> foo = 1
+>> foo = 1
 foo = 1
-octave:13> foo = "bar"
+>> foo = "bar"
 foo = bar
 @end group
 @end example
@@ -1280,14 +1281,149 @@
 @code{a} is a matrix with at least two columns,
 
 @example
-@group
 a(:, 2) = 5
-@end group
 @end example
 
 @noindent
 sets all the elements in the second column of @code{a} to 5.
 
+When an assignment sets the value of a vector, matrix, or array element at a
+position or dimension outside of that variable's current size, the array size
+will be increased to accommodate the new values:
+
+@example
+@group
+>> a = [1, 2, 3]
+a = 1 2 3
+>> a(4) = 4
+a = 1 2 3 4
+>> a(2, :) = [5, 6, 7, 8]
+a =
+   1   2   3   4
+   5   6   7   8
+@end group
+@end example
+
+Attempting to increase the size of an array such that the desired output size
+is ambiguous will result in an error:
+
+@example
+@group
+>> a(9) = 10
+@print{} error: Invalid resizing operation or ambiguous assignment to an
+out-of-bounds array element
+@end group
+@end example
+
+This is because adding the 9th element creates an ambiguity in the desired
+array position for the value 10, each possibility requiring a different array
+size expansion to accommodate the assignment.
+
+Assignments may be made with fewer specified elements than would be required to
+fill the newly expanded array as long as the assignment is unambiguous.  In
+these cases the array will be automatically padded with @i{null} values:
+@example
+@group
+>> a = [1, 2]
+a =   1   2
+>> a(4) = 5
+a =   1   2   0   5
+>> a(3, :) = [6, 7, 8, 9]
+a =
+   1   2   0   5
+   0   0   0   0
+   6   7   8   9
+>> a(4, 5) = 10
+a =
+    1    2    0    5    0
+    0    0    0    0    0
+    6    7    8    9    0
+    0    0    0    0   10
+@end group
+@end example
+
+For all built-in types, the @i{null} value will be appropriate to that object
+type.
+
+Numeric arrays:
+@example
+@group
+>> a = int32 ([1, 2])
+a = 1, 2
+>> a(4) = 5
+a = 1 2 0 5
+@end group
+@end example
+
+Logical arrays:
+@example
+@group
+>> a = [true, false, true]
+a = 1 0 1
+>> d(5) = true
+d = 1 0 1 0 1
+@end group
+@end example
+
+Character arrays:
+@example
+@group
+>> a = "abc"
+a = abc
+>> a(5) = "d"
+a = abcd
+>> double (a)
+ans = 97 98 99 0 100
+@end group
+@end example
+
+Cell arrays:
+@example
+@group
+>> e = @{1, "foo", [3, 4]@};
+>> e(5) = "bar"
+e =
+@{
+  [1,1] = 1
+  [1,2] = foo
+  [1,3] =
+
+     3   4
+
+  [1,4] = [](0x0)
+  [1,5] = bar
+@}
+@end group
+@end example
+
+Struct arrays:
+@example
+@group
+>> a = struct("foo",1,"bar",2);
+>> a(3) = struct("foo",3,"bar",9)
+a =
+
+  1x3 struct array containing the fields:
+
+    foo
+    bar
+
+>> a.foo
+ans = 1
+ans = [](0x0)
+ans = 3
+>> a.bar
+ans = 2
+ans = [](0x0)
+ans = 9
+@end group
+@end example
+
+Note that Octave currently is unable to concatenate arbitrary object types
+into arrays.  Such behavior must be explicitly defined within the object class
+or attempts at concatenation will result in an error.
+@xref{Object Oriented Programming}
+
 Assigning an empty matrix @samp{[]} works in most cases to allow you to
 delete rows or columns of matrices and vectors.  @xref{Empty Matrices}.
 For example, given a 4 by 5 matrix @var{A}, the assignment
@@ -1306,6 +1442,28 @@
 @noindent
 deletes the first, third, and fifth columns.
 
+Deleting part of an array object will necessarily resize the object.  When the
+deletion allows for consistent size reduction across a dimension, e.g., one
+element of a vector, or one row or column of a matrix, the size along that
+dimension will be reduced while preserving dimensionality.  If, however,
+dimensionality cannot be maintained, the object will be reshaped into a vector
+following column-wise element ordering:
+
+@example
+@group
+>> a = [1, 2, 3, 4; 5, 6, 7, 8]
+a =
+   1   2   3   4
+   5   6   7   8
+>> a(:, 3) = []
+a =
+   1   2   4
+   5   6   8
+>> a(4) = []
+a = 1 5 2 4 8
+@end group
+@end example
+
 An assignment is an expression, so it has a value.  Thus, @code{z = 1}
 as an expression has the value 1.  One consequence of this is that you
 can write multiple assignments together:
--- a/libinterp/corefcn/data.cc	Sun Feb 11 09:40:35 2024 -0500
+++ b/libinterp/corefcn/data.cc	Wed Feb 14 18:52:17 2024 -0500
@@ -3818,7 +3818,7 @@
 DEFUN (isempty, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {@var{tf} =} isempty (@var{A})
-Return true if @var{A} is an empty matrix (any one of its dimensions is
+Return true if @var{A} is an empty object (any one of its dimensions is
 zero).
 @seealso{isnull, isa}
 @end deftypefn */)
@@ -3911,9 +3911,9 @@
 @deftypefn {} {@var{tf} =} isvector (@var{x})
 Return true if @var{x} is a vector.
 
-A vector is a 2-D array where one of the dimensions is equal to 1 (either
+A vector is a 2-D object where one of the dimensions is equal to 1 (either
 @nospell{1xN} or @nospell{Nx1}).  As a consequence of this definition, a 1x1
-array (a scalar) is also a vector.
+object (a scalar) is also a vector.
 @seealso{isscalar, ismatrix, iscolumn, isrow, size}
 @end deftypefn */)
 {
@@ -3952,7 +3952,7 @@
 @deftypefn {} {@var{tf} =} isrow (@var{x})
 Return true if @var{x} is a row vector.
 
-A row vector is a 2-D array for which @code{size (@var{x})} returns
+A row vector is a 2-D object for which @code{size (@var{x})} returns
 @w{@code{[1, N]}} with non-negative N.
 @seealso{iscolumn, isscalar, isvector, ismatrix, size}
 @end deftypefn */)
@@ -4001,7 +4001,7 @@
 @deftypefn {} {@var{tf} =} iscolumn (@var{x})
 Return true if @var{x} is a column vector.
 
-A column vector is a 2-D array for which @code{size (@var{x})} returns
+A column vector is a 2-D object for which @code{size (@var{x})} returns
 @w{@code{[N, 1]}} with non-negative N.
 @seealso{isrow, isscalar, isvector, ismatrix, size}
 @end deftypefn */)
--- a/libinterp/corefcn/debug.cc	Sun Feb 11 09:40:35 2024 -0500
+++ b/libinterp/corefcn/debug.cc	Wed Feb 14 18:52:17 2024 -0500
@@ -541,7 +541,7 @@
 %!test
 %! if (isguirunning ())
 %!   orig_show_dbg = __event_manager_gui_preference__ ("editor/show_dbg_file",
-%!                                                     "0");
+%!                                                     "false");
 %! endif
 %! unwind_protect
 %!   dbclear all;   # Clear out breakpoints before test
--- a/libinterp/corefcn/gsvd.cc	Sun Feb 11 09:40:35 2024 -0500
+++ b/libinterp/corefcn/gsvd.cc	Wed Feb 14 18:52:17 2024 -0500
@@ -283,17 +283,17 @@
 %! assert (S0, S1, 20*eps);
 
 ## a few tests for gsvd.m
-%!shared A, A0, B, B0, U, V, C, S, X
+%!shared A0, B0
 %! old_state = randn ("state");
 %! restore_state = onCleanup (@() randn ("state", old_state));
-%! randn ("state", 40); # initialize generator to make behavior reproducible
+%! randn ("state", 40);  # initialize generator to make behavior reproducible
 %! A0 = randn (5, 3);
 %! B0 = diag ([1 2 4]);
-%! A = A0;
-%! B = B0;
 
 ## A (5x3) and B (3x3) are full rank
 %!test <48807>
+%! A = A0;
+%! B = B0;
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (3), 5*eps);
 %! assert (U*C*X', A, 10*eps);
@@ -301,6 +301,8 @@
 
 ## A: 5x3 full rank, B: 3x3 rank deficient
 %!test <48807>
+%! A = A0;
+%! B = B0;
 %! B(2, 2) = 0;
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (3), 5*eps);
@@ -309,6 +311,7 @@
 
 ## A: 5x3 rank deficient, B: 3x3 full rank
 %!test <48807>
+%! A = A0;
 %! B = B0;
 %! A(:, 3) = 2*A(:, 1) - A(:, 2);
 %! [U, V, X, C, S] = gsvd (A, B);
@@ -319,6 +322,8 @@
 ## A and B are both rank deficient
 ## FIXME: LAPACK seems to be completely broken for this case
 %!#test <48807>
+%! A = A0;
+%! B = B0;
 %! B(:, 3) = 2*B(:, 1) - B(:, 2);
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (3), 5*eps);
@@ -328,8 +333,7 @@
 ## A (now 3x5) and B (now 5x5) are full rank
 %!test <48807>
 %! A = A0.';
-%! B0 = diag ([1 2 4 8 16]);
-%! B = B0;
+%! B = diag ([1 2 4 8 16]);
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (5), 5*eps);
 %! assert (U*C*X', A, 15*eps);
@@ -337,6 +341,8 @@
 
 ## A: 3x5 full rank, B: 5x5 rank deficient
 %!test <48807>
+%! A = A0.';
+%! B = diag ([1 2 4 8 16]);
 %! B(2, 2) = 0;
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (5), 5*eps);
@@ -345,7 +351,8 @@
 
 ## A: 3x5 rank deficient, B: 5x5 full rank
 %!test <48807>
-%! B = B0;
+%! A = A0.';
+%! B = diag ([1 2 4 8 16]);
 %! A(3, :) = 2*A(1, :) - A(2, :);
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (5), 5*eps);
@@ -367,11 +374,9 @@
 %!test <48807>
 %! old_state = randn ("state");
 %! restore_state = onCleanup (@() randn ("state", old_state));
-%! randn ("state", 12345); # initialize generator to make behavior reproducible
-%! A0 = A0 + j* randn (5, 3);
-%! B0 = diag ([1 2 4]) + j* diag ([4 -2 -1]);
-%! A = A0;
-%! B = B0;
+%! randn ("state", 12345);  # initialize generator to make behavior reproducible
+%! A = A0 + j* randn (5, 3);
+%! B = diag ([1 2 4]) + j* diag ([4 -2 -1]);
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (3), 5*eps);
 %! assert (U*C*X', A, 10*eps);
@@ -379,6 +384,8 @@
 
 ## A: 5x3 complex full rank, B: 3x3 complex rank deficient
 %!test <48807>
+%! A = A0 + j* randn (5, 3);
+%! B = diag ([1 2 4]) + j* diag ([4 -2 -1]);
 %! B(2, 2) = 0;
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (3), 5*eps);
@@ -387,7 +394,8 @@
 
 ## A: 5x3 complex rank deficient, B: 3x3 complex full rank
 %!test <48807>
-%! B = B0;
+%! A = A0 + j* randn (5, 3);
+%! B = diag ([1 2 4]) + j* diag ([4 -2 -1]);
 %! A(:, 3) = 2*A(:, 1) - A(:, 2);
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (3), 5*eps);
@@ -397,6 +405,8 @@
 ## A (5x3) and B (3x3) are both complex rank deficient
 ## FIXME: LAPACK seems to be completely broken for this case
 %!#test <48807>
+%! A = A0 + j* randn (5, 3);
+%! B = diag ([1 2 4]) + j* diag ([4 -2 -1]);
 %! B(:, 3) = 2*B(:, 1) - B(:, 2);
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (3), 5*eps);
@@ -407,8 +417,7 @@
 ## now, A is 3x5
 %!test <48807>
 %! A = A0.';
-%! B0 = diag ([1 2 4 8 16]) + j* diag ([-5 4 -3 2 -1]);
-%! B = B0;
+%! B = diag ([1 2 4 8 16]) + j* diag ([-5 4 -3 2 -1]);
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (5), 5*eps);
 %! assert (U*C*X', A, 25*eps);
@@ -416,7 +425,8 @@
 
 ## A: 3x5 complex full rank, B: 5x5 complex rank deficient
 %!test <48807>
-%! B(2, 2) = 0;
+%! A = A0.';
+%! B = diag ([1 0 4 8 16]) + j* diag ([-5 0 -3 2 -1]);
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (5), 5*eps);
 %! assert (U*C*X', A, 10*eps);
@@ -424,7 +434,8 @@
 
 ## A: 3x5 complex rank deficient, B: 5x5 complex full rank
 %!test <48807>
-%! B = B0;
+%! A = A0.';
+%! B = diag ([1 2 4 8 16]) + j* diag ([-5 4 -3 2 -1]);
 %! A(3, :) = 2*A(1, :) - A(2, :);
 %! [U, V, X, C, S] = gsvd (A, B);
 %! assert (C'*C + S'*S, eye (5), 5*eps);
@@ -445,9 +456,11 @@
 
 ## Test that single inputs produce single outputs
 %!test
+%! A = A0.';
+%! B = diag ([1 2 4 8 16]) + j* diag ([-5 4 -3 2 -1]);
 %! s = gsvd (single (eye (5)), B);
 %! assert (class (s), "single");
-%! [U,V,X,C,S] = gsvd (single (eye(5)), B);
+%! [U, V, X, C, S] = gsvd (single (eye(5)), B);
 %! assert (class (U), "single");
 %! assert (class (V), "single");
 %! assert (class (X), "single");
@@ -456,7 +469,7 @@
 %!
 %! s = gsvd (A, single (eye (5)));
 %! assert (class (s), "single");
-%! [U,V,X,C,S] = gsvd (A, single (eye (5)));
+%! [U, V, X, C, S] = gsvd (A, single (eye (5)));
 %! assert (class (U), "single");
 %! assert (class (V), "single");
 %! assert (class (X), "single");
--- a/libinterp/corefcn/perms.cc	Sun Feb 11 09:40:35 2024 -0500
+++ b/libinterp/corefcn/perms.cc	Wed Feb 14 18:52:17 2024 -0500
@@ -58,9 +58,9 @@
 // preferrable and the comparison templates can be removed:
 // bool isequal;
 // if constexpr (std::is_same<T, octave_value>::value)
-//   isEqual = Ar[i].is_equal (Ar[j]);
+//   isequal = Ar[i].is_equal (Ar[j]);
 // else
-//   isEqual =  (Ar[i] == Ar[j]);
+//   isequal = (Ar[i] == Ar[j]);
 
 template <typename T>
 bool is_equal_T (T a, T b)
@@ -105,7 +105,7 @@
         {
           for (octave_idx_type j = i + 1; j < m; j++)
             {
-              bool isequal = is_equal_T<T>(Ar[i], Ar[j]);
+              bool isequal = is_equal_T<T> (Ar[i], Ar[j]);
               if (myvidx[j] > myvidx[i] && isequal)
                 {
                   myvidx[j] = myvidx[i];  // not yet processed...
--- a/libinterp/dldfcn/__glpk__.cc	Sun Feb 11 09:40:35 2024 -0500
+++ b/libinterp/dldfcn/__glpk__.cc	Wed Feb 14 18:52:17 2024 -0500
@@ -167,7 +167,7 @@
           break;
         }
 
-      glp_set_row_bnds (lp, i+1, typx, b[i], b[i]);
+      glp_set_row_bnds (lp, i+1, typx, typx == GLP_DB ? -b[i] : b[i], b[i]);
 
     }
 
--- a/libinterp/parse-tree/bp-table.cc	Sun Feb 11 09:40:35 2024 -0500
+++ b/libinterp/parse-tree/bp-table.cc	Wed Feb 14 18:52:17 2024 -0500
@@ -543,18 +543,28 @@
 
 /*
 %!test
-%! dbclear all;   # Clear out breakpoints before test
-%! dbstop help;
-%! dbstop in ls;
-%! dbstop help at 105;  # 105 is a comment; code line is at 106
-%! dbstop in ls 123;    # 123 is a comment; code line is at 126
-%! dbstop help 204 if a==5;
-%! dbstop if error Octave:undefined-function;
-%! s = dbstatus;
-%! dbclear all;
-%! assert ({s.bkpt(:).name}, {"help", "help", "help>do_contents", "ls", "ls"});
-%! assert ([s.bkpt(:).line], [56, 106, 208, 63, 126]);
-%! assert (s.errs, {"Octave:undefined-function"});
+%! if (isguirunning ())
+%!   orig_show_dbg = __event_manager_gui_preference__ ("editor/show_dbg_file",
+%!                                                     "false");
+%! endif
+%! unwind_protect
+%!   dbclear all;   # Clear out breakpoints before test
+%!   dbstop help;
+%!   dbstop in ls;
+%!   dbstop help at 105;  # 105 is a comment; code line is at 106
+%!   dbstop in ls 123;    # 123 is a comment; code line is at 126
+%!   dbstop help 204 if a==5;
+%!   dbstop if error Octave:undefined-function;
+%!   s = dbstatus;
+%!   dbclear all;
+%!   assert ({s.bkpt(:).name}, {"help", "help", "help>do_contents", "ls", "ls"});
+%!   assert ([s.bkpt(:).line], [56, 106, 208, 63, 126]);
+%!   assert (s.errs, {"Octave:undefined-function"});
+%! unwind_protect_cleanup
+%!   if (isguirunning ())
+%!     __event_manager_gui_preference__ ("editor/show_dbg_file", orig_show_dbg);
+%!   endif
+%! end_unwind_protect
 */
 
 void
--- a/libinterp/parse-tree/pt-eval.cc	Sun Feb 11 09:40:35 2024 -0500
+++ b/libinterp/parse-tree/pt-eval.cc	Wed Feb 14 18:52:17 2024 -0500
@@ -3249,7 +3249,7 @@
       if (rhs.ndims () > 2)
         arg = arg.reshape (dv);
 
-      if (nrows > 0 && steps > 0)
+      if (steps > 0)
         {
           octave_value_list idx;
           octave_idx_type iidx;
--- a/scripts/optimization/glpk.m	Sun Feb 11 09:40:35 2024 -0500
+++ b/scripts/optimization/glpk.m	Wed Feb 14 18:52:17 2024 -0500
@@ -652,6 +652,22 @@
 %!   assert (A(i,:) * xmin <= b(i));
 %! endfor
 
+%!testif HAVE_GLPK
+%! sense = 1;
+%! c = [-1, -1]';
+%! A = [1, 0; 0, 1];
+%! b = [1, 1]';
+%! ctype = ['D', 'D']';
+%! lb = [-1, -1]';
+%! ub = [];
+%! vartype = ['I', 'I']';
+%! param.msglev = 0;
+%! [xmin, fmin, errnum, extra] = glpk (c, A, b, lb, ub, ctype, vartype, ...
+%!   sense, param);
+%! assert (fmin, c' * xmin);
+%! for i = 1:2
+%!   assert (A(i,:) * xmin <= b(i));
+%! endfor
 
 %!testif HAVE_GLPK
 %! sense = 1;
--- a/test/classdef-debug/test_classdef_breakpoints.tst	Sun Feb 11 09:40:35 2024 -0500
+++ b/test/classdef-debug/test_classdef_breakpoints.tst	Wed Feb 14 18:52:17 2024 -0500
@@ -10,22 +10,40 @@
 %!  endif
 %!endfunction
 
-## Add breakpoints in different member functions using line numbers.
 %!test <*46451>
-%! dbstop classdef_breakpoints 13 7 10;
-%! assert_dbstatus ([7, 10, 13]);
-
-## Remove one breakpoint and confirm the others remain.
-%!test <*46451>
-%! dbclear classdef_breakpoints 10;
-%! assert_dbstatus ([7, 13]);
+%! if (isguirunning ())
+%!   orig_show_dbg = __event_manager_gui_preference__ ("editor/show_dbg_file",
+%!                                                     "false");
+%! endif
+%! unwind_protect
+%!   ## Add breakpoints in different member functions using line numbers.
+%!   dbstop classdef_breakpoints 13 7 10;
+%!   assert_dbstatus ([7, 10, 13]);
+%!
+%!   ## Remove one breakpoint and confirm the others remain.
+%!   dbclear classdef_breakpoints 10;
+%!   assert_dbstatus ([7, 13]);
+%!
+%!   ## Clear all breakpoints, none should be left.
+%!   dbclear classdef_breakpoints;
+%!   assert_dbstatus ([]);
+%! unwind_protect_cleanup
+%!   if (isguirunning ())
+%!     __event_manager_gui_preference__ ("editor/show_dbg_file", orig_show_dbg);
+%!   endif
+%! end_unwind_protect
 
-## Add breakpoint in local function.
 %!test <46451>
-%! dbstop classdef_breakpoints 19;
-%! assert_dbstatus ([7, 13, 20]);
-
-## Clear all breakpoints, none should be left.
-%!test <*46451>
-%! dbclear classdef_breakpoints;
-%! assert_dbstatus ([]);
+%! if (isguirunning ())
+%!   orig_show_dbg = __event_manager_gui_preference__ ("editor/show_dbg_file",
+%!                                                     "false");
+%! endif
+%! unwind_protect
+%!   ## Add breakpoint in local function.
+%!   dbstop classdef_breakpoints 19;
+%!   assert_dbstatus ([7, 13, 20]);
+%! unwind_protect_cleanup
+%!   if (isguirunning ())
+%!     __event_manager_gui_preference__ ("editor/show_dbg_file", orig_show_dbg);
+%!   endif
+%! end_unwind_protect
--- a/test/for.tst	Sun Feb 11 09:40:35 2024 -0500
+++ b/test/for.tst	Wed Feb 14 18:52:17 2024 -0500
@@ -130,15 +130,15 @@
 %! __printf_assert__ ("\n");
 %! assert (__prog_output_assert__ ("1234"));
 
-%!test <*50893>
+%!test <*55622>
 %! cnt = 0;
 %! for k = zeros (0,3)
 %!   cnt++;
 %! endfor
-%! assert (cnt, 0);
-%! assert (k, zeros (0,3));
+%! assert (cnt, 3);
+%! assert (k, zeros (0,1));
 
-%!test <*50893>
+%!test <*55622>
 %! cnt = 0;
 %! for k = zeros (3,0)
 %!   cnt++;
@@ -159,8 +159,24 @@
 %! for k = cell (0,3)
 %!   cnt++;
 %! endfor
+%! assert (cnt, 3);
+%! assert (k, cell (0,1));
+
+%!test <*55622>
+%! cnt = 0;
+%! for k = zeros (1,2,3);
+%!   cnt++;
+%! endfor
+%! assert (cnt, 6);
+%! assert (k, 0);
+
+%!test <*55622>
+%! cnt = 0;
+%! for k = zeros (1,2,0);
+%!   cnt++;
+%! endfor
 %! assert (cnt, 0);
-%! assert (k, cell (0,3));
+%! assert (k, zeros (1,0));
 
 %!test <*45143>
 %! warning ("on", "Octave:infinite-loop", "local");