Mercurial > octave
changeset 32446:d0b363fd92c5
Support to few return values from anon. func. in bc-vm
There was a bug when a constant as root expression would not
produce enough return values.
E.g. 'h = @() 1; [a b] = h();' would trigger an internal
assert.
* pt-bytecode-vm.cc: Accept 0 <= k <= nargout ret. values
* bytecode_anon_handles.m: Update test
author | Petter T. |
---|---|
date | Fri, 27 Oct 2023 18:20:09 +0200 |
parents | 4d6615bca5b4 |
children | 53920541c0b8 |
files | libinterp/parse-tree/pt-bytecode-vm.cc test/compile/bytecode_anon_handles.m |
diffstat | 2 files changed, 39 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/parse-tree/pt-bytecode-vm.cc Fri Oct 27 18:20:03 2023 +0200 +++ b/libinterp/parse-tree/pt-bytecode-vm.cc Fri Oct 27 18:20:09 2023 +0200 @@ -5972,16 +5972,19 @@ assert (N_RETURNS () == -128); - int n_returns_callee = bsp[0].i + 1; // Nargout on stack, +1 to include %nargout - if (n_returns_callee == 1) - n_returns_callee = 2; + int n_returns_callee = bsp[0].i; // Nargout on stack + if (n_returns_callee == 0) + n_returns_callee = 1; int n_locals_callee = N_LOCALS (); // Amount of arguments, purely local variables and %nargout - // Assert that the stack pointer is back where it should be - assert (bsp + n_locals_callee + n_returns_callee - 1 == sp); - - stack_element *first_ret = sp - n_returns_callee + 1; + int n_ret_on_stack = sp - bsp - n_locals_callee; + + // Assert that the stack pointer is back where it should be, i.e. that there are between + // zero and nargout return values. + assert (n_ret_on_stack >= 0 && n_ret_on_stack <= n_returns_callee); + + stack_element *first_ret = sp - n_ret_on_stack; // Destroy locals // @@ -6027,16 +6030,16 @@ int j; // nargout 0 should still give one return value, if there is one int n_root_wanted = std::max (root_nargout, 1); - for (j = 1; j < n_returns_callee && j < (n_root_wanted + 1); j++) + for (j = 0; j < n_ret_on_stack && j < n_root_wanted; j++) { - int idx = (n_returns_callee - 1) - j; + int idx = n_ret_on_stack - 1 - j; ret.append (std::move (first_ret[idx].ov)); first_ret[idx].ov.~octave_value (); } // Destroy rest of return values, if any - for (; j < n_returns_callee; j++) + for (; j < n_ret_on_stack; j++) { - int idx = (n_returns_callee - 1) - j; + int idx = n_ret_on_stack - j; first_ret[idx].ov.~octave_value (); } @@ -6093,7 +6096,7 @@ // Move the callee's return values to the top of the stack of the caller. // Renaming variables to keep my sanity. int n_args_caller_expects = caller_nval_back; - int n_args_callee_has = n_returns_callee - 1; // Excludes %nargout + int n_args_callee_has = n_ret_on_stack; // Excludes %nargout int n_args_to_move = std::min (n_args_caller_expects, n_args_callee_has); int n_args_actually_moved = 0;
--- a/test/compile/bytecode_anon_handles.m Fri Oct 27 18:20:03 2023 +0200 +++ b/test/compile/bytecode_anon_handles.m Fri Oct 27 18:20:09 2023 +0200 @@ -107,6 +107,30 @@ assert (h2 (3) == 6) h2 = @(yy) execute_handle (@(yyyy) execute_handle (@(yyy) h1 (yyy), yyyy), yy); % Nest some more assert (h2 (3) == 6) + + % Test not enough return values + threw = false; + try + h1 = @() 1; + [a, b] = h1 (); + catch + threw = true; + end + + assert (threw); + + h1 = @(varargin) varargin{:}; + [a b c] = h1(1,2,3); + assert ([a b c] == [1 2 3]) + + threw = false; + try + [a b c d] = h1(1,2,3); + catch + threw = true; + end + + assert (threw); end function [x, y, z] = try_isargout ()