changeset 28540:ea5a632b2553 stable

improve error checking for undefined function outputs (bug #58686, #58695) * pt-eval.h, pt-eval.cc (tree_evaluator::bind_auto_fcn_vars): New argument, ignored_outputs. (tree_evaluator::convert_return_list_to_const_vector): New argument, ignored_outputs. Improve handling of undefined output values and ignored outputs. (tree_evaluator::execute_user_function): Call ignored_fcn_outputs here and pass result to bind_auto_fcn_vars. Also pass array of ignored_fcn_outputs to convert_return_list_to_const_vector. * pt-assign.cc: New tests.
author John W. Eaton <jwe@octave.org>
date Tue, 07 Jul 2020 18:34:23 -0400
parents c09bc9e108b5
children 5f4e8dddf05f c318254c9f01
files libinterp/parse-tree/pt-assign.cc libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h
diffstat 3 files changed, 85 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/parse-tree/pt-assign.cc	Tue Jul 07 13:12:48 2020 -0400
+++ b/libinterp/parse-tree/pt-assign.cc	Tue Jul 07 18:34:23 2020 -0400
@@ -350,14 +350,34 @@
 }
 
 /*
-%!function varargout = f ()
+%!function varargout = f1 ()
 %!  varargout{1} = nargout;
 %!endfunction
 %!
 %!test
-%! [a, ~] = f ();
+%! [a, ~] = f1 ();
 %! assert (a, 2);
 %!test
-%! [a, ~, ~, ~, ~] = f ();
+%! [a, ~, ~, ~, ~] = f1 ();
 %! assert (a, 5);
+
+%!function [x, y] = f2 ()
+%!  y = 1;
+%!endfunction
+%!
+%!test
+%! [~, y] = f2 ();
+%! assert (y, 1);
+
+%!function [x, y, varargout] = f3 ()
+%!  y = 1;
+%!  varargout = {2, 3};
+%!endfunction
+%!
+%!test
+%! [~, y, a, b] = f3 ();
+%! assert ([y, a, b], [1, 2, 3]);
+%!test
+%! [~, y, ~, b] = f3 ();
+%! assert ([y, b], [1, 3]);
 */
--- a/libinterp/parse-tree/pt-eval.cc	Tue Jul 07 13:12:48 2020 -0400
+++ b/libinterp/parse-tree/pt-eval.cc	Tue Jul 07 18:34:23 2020 -0400
@@ -1788,7 +1788,8 @@
 
   octave_value_list
   tree_evaluator::convert_return_list_to_const_vector
-    (tree_parameter_list *ret_list, int nargout, const Cell& varargout)
+    (tree_parameter_list *ret_list, int nargout, const Matrix& ignored_outputs,
+     const Cell& varargout)
   {
     octave_idx_type vlen = varargout.numel ();
     int len = ret_list->length ();
@@ -1796,35 +1797,59 @@
     // Special case.  Will do a shallow copy.
     if (len == 0)
       return varargout;
-    else if (nargout <= len)
-      {
-        octave_value_list retval (nargout);
-
-        int i = 0;
-
-        for (tree_decl_elt *elt : *ret_list)
-          {
-            if (is_defined (elt->ident ()))
-              retval(i) = evaluate (elt);
-
-            i++;
-          }
-
-        return retval;
-      }
     else
       {
-        octave_value_list retval (len + vlen);
-
         int i = 0;
-
-        for (tree_decl_elt *elt : *ret_list)
-          retval(i++) = evaluate (elt);
-
-        for (octave_idx_type j = 0; j < vlen; j++)
-          retval(i++) = varargout(j);
-
-        return retval;
+        int k = 0;
+        int num_ignored = ignored_outputs.numel ();
+        int ignored = num_ignored > 0 ? ignored_outputs(k) - 1 : -1;
+
+        if (nargout <= len)
+          {
+            int nout = nargout > 0 ? nargout : 1;
+            octave_value_list retval (nout);
+
+            for (tree_decl_elt *elt : *ret_list)
+              {
+                if (nargout == 0 && ! is_defined (elt->ident ()))
+                  break;
+
+                if (ignored >= 0 && i == ignored)
+                  {
+                    i++;
+                    k++;
+                    ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1;
+                  }
+                else
+                  retval(i++) = evaluate (elt);
+
+                if (i == nout)
+                  break;
+              }
+
+            return retval;
+          }
+        else
+          {
+            octave_value_list retval (len + vlen);
+
+            for (tree_decl_elt *elt : *ret_list)
+              {
+                if (ignored >= 0 && i == ignored)
+                  {
+                    i++;
+                    k++;
+                    ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1;
+                  }
+                else
+                  retval(i++) = evaluate (elt);
+              }
+
+            for (octave_idx_type j = 0; j < vlen; j++)
+              retval(i++) = varargout(j);
+
+            return retval;
+          }
       }
   }
 
@@ -2759,7 +2784,9 @@
     if (m_call_stack.size () >= static_cast<size_t> (m_max_recursion_depth))
       error ("max_recursion_depth exceeded");
 
-    bind_auto_fcn_vars (xargs.name_tags (), args.length (),
+    Matrix ignored_outputs = ignored_fcn_outputs ();
+
+    bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, args.length (),
                         nargout, user_function.takes_varargs (),
                         user_function.all_va_args (args));
 
@@ -2841,6 +2868,7 @@
           }
 
         retval = convert_return_list_to_const_vector (ret_list, nargout,
+                                                      ignored_outputs,
                                                       varargout);
       }
 
@@ -4158,12 +4186,13 @@
   }
 
   void tree_evaluator::bind_auto_fcn_vars (const string_vector& arg_names,
+                                           const Matrix& ignored_outputs,
                                            int nargin, int nargout,
                                            bool takes_varargs,
                                            const octave_value_list& va_args)
   {
     set_auto_fcn_var (stack_frame::ARG_NAMES, Cell (arg_names));
-    set_auto_fcn_var (stack_frame::IGNORED, ignored_fcn_outputs ());
+    set_auto_fcn_var (stack_frame::IGNORED, ignored_outputs);
     set_auto_fcn_var (stack_frame::NARGIN, nargin);
     set_auto_fcn_var (stack_frame::NARGOUT, nargout);
     set_auto_fcn_var (stack_frame::SAVED_WARNING_STATES, octave_value ());
--- a/libinterp/parse-tree/pt-eval.h	Tue Jul 07 13:12:48 2020 -0400
+++ b/libinterp/parse-tree/pt-eval.h	Tue Jul 07 18:34:23 2020 -0400
@@ -361,7 +361,8 @@
 
     octave_value_list
     convert_return_list_to_const_vector
-      (tree_parameter_list *ret_list, int nargout, const Cell& varargout);
+      (tree_parameter_list *ret_list, int nargout,
+       const Matrix& ignored_outputs, const Cell& varargout);
 
     bool eval_decl_elt (tree_decl_elt *elt);
 
@@ -739,7 +740,8 @@
 
     bool quit_loop_now (void);
 
-    void bind_auto_fcn_vars (const string_vector& arg_names, int nargin,
+    void bind_auto_fcn_vars (const string_vector& arg_names,
+                             const Matrix& ignored_outputs, int nargin,
                              int nargout, bool takes_varargs,
                              const octave_value_list& va_args);