changeset 23481:73558a835b64

eliminate lvalue list arguments from evaluator functions * ov.cc, ov.h, ov-base.cc, ov-base.h, ov-builtin.cc, ov-builtin.h, ov-cell.cc, ov-cell.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-usr-fcn.cc, ov-usr-fcn.h: Eliminate lvalue_list arguments from subsref, next_subsref, and do_multi_index_op methods. Change all callers. * pt-eval.cc, pt-eval.h (tree_evaluator::ignored_fcn_outputs): New function. * ov-usr-fcn.h, ov-usr-fcn.cc (octave_user_function::bind_automatic_vars): Get list of ignored output arguments from evaluator. * pt-eval.cc, pt-eval.h (tree_evaluator::visit_simple_assignment, tree_evaluator::visit_multi_assignment): Push lvalue list on stack here, not in tree_evaluator::evaluate or tree_evaluator::evaluate_n. Use unwind_protect frame to pop from stack. Don't pass lvalue list to evaluate or evaluate_n functions. * pt-arg-list.cc, pt-arg-list.h (tree_argument_list::lvalue_list): Delete. * pt-eval.cc, pt-eval.h (tree_evaluator::make_lvalue_list): New function. (tree_evaluator::visit_multi_assignment): Use it instead of tree_argument_list::lvalue_list. * ov-builtin.cc, ov-builtin.h (octave_builtin::curr_lvalue_list): Delete data member and all uses. * defun.cc (defun_isargout): Get current lvalue_list from evaluator.
author John W. Eaton <jwe@octave.org>
date Wed, 10 May 2017 11:09:52 -0400
parents 0670624ea91b
children c9937e865768
files libinterp/corefcn/defun.cc libinterp/octave-value/ov-base.cc libinterp/octave-value/ov-base.h libinterp/octave-value/ov-builtin.cc libinterp/octave-value/ov-builtin.h libinterp/octave-value/ov-cell.cc libinterp/octave-value/ov-cell.h libinterp/octave-value/ov-fcn-handle.cc libinterp/octave-value/ov-fcn-handle.h libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov-usr-fcn.h libinterp/octave-value/ov.cc libinterp/octave-value/ov.h libinterp/parse-tree/pt-arg-list.cc libinterp/parse-tree/pt-arg-list.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h
diffstat 17 files changed, 133 insertions(+), 286 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/defun.cc	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/corefcn/defun.cc	Wed May 10 11:09:52 2017 -0400
@@ -42,8 +42,10 @@
 #include "ovl.h"
 #include "oct-lvalue.h"
 #include "pager.h"
+#include "pt-eval.h"
+#include "interpreter-private.h"
+#include "interpreter.h"
 #include "symtab.h"
-#include "interpreter.h"
 #include "variables.h"
 #include "parse.h"
 
@@ -158,7 +160,7 @@
 bool defun_isargout (int nargout, int iout)
 {
   const std::list<octave_lvalue> *lvalue_list
-    = octave_builtin::curr_lvalue_list;
+    = octave::current_evaluator->lvalue_list ();
 
   if (iout >= std::max (nargout, 1))
     return false;
@@ -183,7 +185,7 @@
 void defun_isargout (int nargout, int nout, bool *isargout)
 {
   const std::list<octave_lvalue> *lvalue_list
-    = octave_builtin::curr_lvalue_list;
+    = octave::current_evaluator->lvalue_list ();
 
   if (lvalue_list)
     {
--- a/libinterp/octave-value/ov-base.cc	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov-base.cc	Wed May 10 11:09:52 2017 -0400
@@ -238,16 +238,6 @@
   return subsref (type, idx);
 }
 
-octave_value_list
-octave_base_value::subsref (const std::string& type,
-                            const std::list<octave_value_list>& idx,
-                            int nargout,
-                            const std::list<octave_lvalue> *)
-{
-  // Fall back to call without passing lvalue list.
-  return subsref (type, idx, nargout);
-}
-
 octave_value
 octave_base_value::do_index_op (const octave_value_list&, bool)
 {
@@ -262,14 +252,6 @@
   error ("can't perform indexing operations for %s type", nm.c_str ());
 }
 
-octave_value_list
-octave_base_value::do_multi_index_op (int nargout, const octave_value_list& idx,
-                                      const std::list<octave_lvalue> *)
-{
-  // Fall back.
-  return do_multi_index_op (nargout, idx);
-}
-
 idx_vector
 octave_base_value::index_vector (bool /* require_integers */) const
 {
--- a/libinterp/octave-value/ov-base.h	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov-base.h	Wed May 10 11:09:52 2017 -0400
@@ -275,22 +275,12 @@
            const std::list<octave_value_list>& idx,
            bool auto_add);
 
-  virtual octave_value_list
-  subsref (const std::string& type,
-           const std::list<octave_value_list>& idx,
-           int nargout,
-           const std::list<octave_lvalue> *lvalue_list);
-
   virtual octave_value
   do_index_op (const octave_value_list& idx, bool resize_ok = false);
 
   virtual octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& idx);
 
-  virtual octave_value_list
-  do_multi_index_op (int nargout, const octave_value_list& idx,
-                     const std::list<octave_lvalue> *lvalue_list);
-
   virtual void assign (const std::string&, const octave_value&) { }
 
   virtual octave_value
--- a/libinterp/octave-value/ov-builtin.cc	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov-builtin.cc	Wed May 10 11:09:52 2017 -0400
@@ -44,15 +44,6 @@
                          const std::list<octave_value_list>& idx,
                          int nargout)
 {
-  return octave_builtin::subsref (type, idx, nargout, 0);
-}
-
-octave_value_list
-octave_builtin::subsref (const std::string& type,
-                         const std::list<octave_value_list>& idx,
-                         int nargout,
-                         const std::list<octave_lvalue>* lvalue_list)
-{
   octave_value_list retval;
 
   switch (type[0])
@@ -61,8 +52,7 @@
       {
         int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
 
-        retval = do_multi_index_op (tmp_nargout, idx.front (),
-                                    idx.size () == 1 ? lvalue_list : 0);
+        retval = do_multi_index_op (tmp_nargout, idx.front ());
       }
       break;
 
@@ -97,13 +87,6 @@
 octave_value_list
 octave_builtin::do_multi_index_op (int nargout, const octave_value_list& args)
 {
-  return octave_builtin::do_multi_index_op (nargout, args, 0);
-}
-
-octave_value_list
-octave_builtin::do_multi_index_op (int nargout, const octave_value_list& args,
-                                   const std::list<octave_lvalue> *lvalue_list)
-{
   octave_value_list retval;
 
   if (args.has_magic_colon ())
@@ -115,12 +98,6 @@
 
   frame.add_fcn (octave::call_stack::pop);
 
-  if (lvalue_list || curr_lvalue_list)
-    {
-      frame.protect_var (curr_lvalue_list);
-      curr_lvalue_list = lvalue_list;
-    }
-
   profile_data_accumulator::enter<octave_builtin> block (profiler, *this);
 
   retval = (*f) (args, nargout);
@@ -176,5 +153,3 @@
 {
   return dispatch_classes.find (dispatch_type) != dispatch_classes.end ();
 }
-
-const std::list<octave_lvalue> *octave_builtin::curr_lvalue_list = nullptr;
--- a/libinterp/octave-value/ov-builtin.h	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov-builtin.h	Wed May 10 11:09:52 2017 -0400
@@ -77,11 +77,6 @@
                              const std::list<octave_value_list>& idx,
                              int nargout);
 
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx,
-                             int nargout,
-                             const std::list<octave_lvalue>* lvalue_list);
-
   octave_function * function_value (bool = false) { return this; }
 
   bool is_builtin_function (void) const { return true; }
@@ -89,10 +84,6 @@
   octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& args);
 
-  octave_value_list
-  do_multi_index_op (int nargout, const octave_value_list& args,
-                     const std::list<octave_lvalue>* lvalue_list);
-
   jit_type * to_jit (void) const;
 
   void stash_jit (jit_type& type);
@@ -103,8 +94,6 @@
 
   bool handles_dispatch_class (const std::string& dispatch_type) const;
 
-  static const std::list<octave_lvalue> *curr_lvalue_list;
-
 protected:
 
   // A pointer to the actual function.
--- a/libinterp/octave-value/ov-cell.cc	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov-cell.cc	Wed May 10 11:09:52 2017 -0400
@@ -131,8 +131,7 @@
 octave_value_list
 octave_cell::subsref (const std::string& type,
                       const std::list<octave_value_list>& idx,
-                      int nargout,
-                      const std::list<octave_lvalue> *lvalue_list)
+                      int nargout)
 {
   octave_value_list retval;
 
@@ -174,9 +173,7 @@
   // octave_user_function::subsref.
 
   if (idx.size () > 1)
-    retval = (lvalue_list
-              ? retval(0).next_subsref (nargout, type, idx, lvalue_list)
-              : retval(0).next_subsref (nargout, type, idx));
+    retval = retval(0).next_subsref (nargout, type, idx);
 
   return retval;
 }
--- a/libinterp/octave-value/ov-cell.h	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov-cell.h	Wed May 10 11:09:52 2017 -0400
@@ -80,15 +80,7 @@
 
   octave_value_list subsref (const std::string& type,
                              const std::list<octave_value_list>& idx,
-                             int nargout)
-  {
-    return subsref (type, idx, nargout, 0);
-  }
-
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx,
-                             int nargout,
-                             const std::list<octave_lvalue> *lvalue_list);
+                             int nargout);
 
   octave_value subsref (const std::string& type,
                         const std::list<octave_value_list>& idx,
--- a/libinterp/octave-value/ov-fcn-handle.cc	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Wed May 10 11:09:52 2017 -0400
@@ -96,15 +96,6 @@
                             const std::list<octave_value_list>& idx,
                             int nargout)
 {
-  return octave_fcn_handle::subsref (type, idx, nargout, 0);
-}
-
-octave_value_list
-octave_fcn_handle::subsref (const std::string& type,
-                            const std::list<octave_value_list>& idx,
-                            int nargout,
-                            const std::list<octave_lvalue>* lvalue_list)
-{
   octave_value_list retval;
 
   switch (type[0])
@@ -113,8 +104,7 @@
       {
         int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
 
-        retval = do_multi_index_op (tmp_nargout, idx.front (),
-                                    idx.size () == 1 ? lvalue_list : 0);
+        retval = do_multi_index_op (tmp_nargout, idx.front ());
       }
       break;
 
@@ -144,14 +134,6 @@
 octave_fcn_handle::do_multi_index_op (int nargout,
                                       const octave_value_list& args)
 {
-  return do_multi_index_op (nargout, args, 0);
-}
-
-octave_value_list
-octave_fcn_handle::do_multi_index_op (int nargout,
-                                      const octave_value_list& args,
-                                      const std::list<octave_lvalue>* lvalue_list)
-{
   octave_value_list retval;
 
   out_of_date_check (fcn, "", false);
@@ -213,9 +195,9 @@
         }
 
       if (ov_fcn.is_defined ())
-        retval = ov_fcn.do_multi_index_op (nargout, args, lvalue_list);
+        retval = ov_fcn.do_multi_index_op (nargout, args);
       else if (fcn.is_defined ())
-        retval = fcn.do_multi_index_op (nargout, args, lvalue_list);
+        retval = fcn.do_multi_index_op (nargout, args);
       else
         error ("%s: no method for class %s",
                nm.c_str (), dispatch_type.c_str ());
@@ -224,7 +206,7 @@
     {
       // Non-overloaded function (anonymous, subfunction, private function).
       if (fcn.is_defined ())
-        retval = fcn.do_multi_index_op (nargout, args, lvalue_list);
+        retval = fcn.do_multi_index_op (nargout, args);
       else
         error ("%s: no longer valid function handle", nm.c_str ());
     }
@@ -2089,14 +2071,6 @@
 octave_fcn_binder::do_multi_index_op (int nargout,
                                       const octave_value_list& args)
 {
-  return do_multi_index_op (nargout, args, 0);
-}
-
-octave_value_list
-octave_fcn_binder::do_multi_index_op (int nargout,
-                                      const octave_value_list& args,
-                                      const std::list<octave_lvalue>* lvalue_list)
-{
   octave_value_list retval;
 
   if (args.length () == expected_nargin)
@@ -2111,10 +2085,10 @@
       // Make a shallow copy of arg_template, to ensure consistency throughout
       // the following call even if we happen to get back here.
       octave_value_list tmp (arg_template);
-      retval = root_handle.do_multi_index_op (nargout, tmp, lvalue_list);
+      retval = root_handle.do_multi_index_op (nargout, tmp);
     }
   else
-    retval = octave_fcn_handle::do_multi_index_op (nargout, args, lvalue_list);
+    retval = octave_fcn_handle::do_multi_index_op (nargout, args);
 
   return retval;
 }
--- a/libinterp/octave-value/ov-fcn-handle.h	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov-fcn-handle.h	Wed May 10 11:09:52 2017 -0400
@@ -90,18 +90,9 @@
                              const std::list<octave_value_list>& idx,
                              int nargout);
 
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx,
-                             int nargout,
-                             const std::list<octave_lvalue>* lvalue_list);
-
   octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& args);
 
-  octave_value_list
-  do_multi_index_op (int nargout, const octave_value_list& args,
-                     const std::list<octave_lvalue>* lvalue_list);
-
   bool is_defined (void) const { return true; }
 
   bool is_function_handle (void) const { return true; }
@@ -211,10 +202,6 @@
   octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& args);
 
-  octave_value_list
-  do_multi_index_op (int nargout, const octave_value_list& args,
-                     const std::list<octave_lvalue>* lvalue_list);
-
 protected:
 
   octave_value root_handle;
--- a/libinterp/octave-value/ov-usr-fcn.cc	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Wed May 10 11:09:52 2017 -0400
@@ -410,15 +410,6 @@
                                const std::list<octave_value_list>& idx,
                                int nargout)
 {
-  return octave_user_function::subsref (type, idx, nargout, 0);
-}
-
-octave_value_list
-octave_user_function::subsref (const std::string& type,
-                               const std::list<octave_value_list>& idx,
-                               int nargout,
-                               const std::list<octave_lvalue>* lvalue_list)
-{
   octave_value_list retval;
 
   switch (type[0])
@@ -427,8 +418,7 @@
       {
         int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
 
-        retval = do_multi_index_op (tmp_nargout, idx.front (),
-                                    idx.size () == 1 ? lvalue_list : 0);
+        retval = do_multi_index_op (tmp_nargout, idx.front ());
       }
       break;
 
@@ -456,15 +446,7 @@
 
 octave_value_list
 octave_user_function::do_multi_index_op (int nargout,
-                                         const octave_value_list& args)
-{
-  return do_multi_index_op (nargout, args, 0);
-}
-
-octave_value_list
-octave_user_function::do_multi_index_op (int nargout,
-                                         const octave_value_list& _args,
-                                         const std::list<octave_lvalue>* lvalue_list)
+                                         const octave_value_list& _args)
 {
   octave_value_list retval;
 
@@ -570,8 +552,8 @@
       frame.add_fcn (symbol_table::clear_variables);
     }
 
-  bind_automatic_vars (arg_names, args.length (), nargout,
-                       all_va_args (args), lvalue_list);
+  bind_automatic_vars (tw, arg_names, args.length (), nargout,
+                       all_va_args (args));
 
   frame.add_method (this, &octave_user_function::restore_warning_states);
 
@@ -607,7 +589,7 @@
           {
             octave::call_stack::set_location (stmt->line (), stmt->column ());
 
-            retval = tw->evaluate_n (expr, nargout, lvalue_list);
+            retval = tw->evaluate_n (expr, nargout);
           }
       }
     else
@@ -705,9 +687,8 @@
 
 void
 octave_user_function::bind_automatic_vars
-  (const string_vector& arg_names, int nargin, int nargout,
-   const octave_value_list& va_args,
-   const std::list<octave_lvalue> *lvalue_list)
+  (octave::tree_evaluator *tw, const string_vector& arg_names,
+   int nargin, int nargout, const octave_value_list& va_args)
 {
   if (! arg_names.empty ())
     {
@@ -743,31 +724,12 @@
   if (takes_varargs ())
     symbol_table::assign ("varargin", va_args.cell_value ());
 
-  // Force .ignored. variable to be undefined by default.
-  symbol_table::assign (".ignored.");
-
-  if (lvalue_list)
-    {
-      octave_idx_type nbh = 0;
-      for (const auto& lval : *lvalue_list)
-        nbh += lval.is_black_hole ();
+  Matrix ignored_fcn_outputs = tw ? tw->ignored_fcn_outputs () : Matrix ();
 
-      if (nbh > 0)
-        {
-          // Only assign the hidden variable if black holes actually present.
-          Matrix bh (1, nbh);
-          octave_idx_type k = 0;
-          octave_idx_type l = 0;
-          for (const auto& lval : *lvalue_list)
-            {
-              if (lval.is_black_hole ())
-                bh(l++) = k+1;
-              k += lval.numel ();
-            }
-
-          symbol_table::assign (".ignored.", bh);
-        }
-    }
+  if (ignored_fcn_outputs.is_empty ())
+    symbol_table::assign (".ignored.");
+  else
+    symbol_table::assign (".ignored.", ignored_fcn_outputs);
 
   symbol_table::mark_hidden (".ignored.");
   symbol_table::mark_automatic (".ignored.");
--- a/libinterp/octave-value/ov-usr-fcn.h	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov-usr-fcn.h	Wed May 10 11:09:52 2017 -0400
@@ -45,6 +45,7 @@
 {
   class tree_parameter_list;
   class tree_statement_list;
+  class tree_evaluator;
   class tree_expression;
   class tree_walker;
 }
@@ -370,18 +371,9 @@
                              const std::list<octave_value_list>& idx,
                              int nargout);
 
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx,
-                             int nargout,
-                             const std::list<octave_lvalue>* lvalue_list);
-
   octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& args);
 
-  octave_value_list
-  do_multi_index_op (int nargout, const octave_value_list& args,
-                     const std::list<octave_lvalue>* lvalue_list);
-
   octave::tree_parameter_list * parameter_list (void) { return param_list; }
 
   octave::tree_parameter_list * return_list (void) { return ret_list; }
@@ -517,9 +509,10 @@
 
   void print_code_function_trailer (void);
 
-  void bind_automatic_vars (const string_vector& arg_names, int nargin,
-                            int nargout, const octave_value_list& va_args,
-                            const std::list<octave_lvalue> *lvalue_list);
+  void bind_automatic_vars (octave::tree_evaluator *tw,
+                            const string_vector& arg_names,
+                            int nargin, int nargout,
+                            const octave_value_list& va_args);
 
   void restore_warning_states (void);
 
--- a/libinterp/octave-value/ov.cc	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov.cc	Wed May 10 11:09:52 2017 -0400
@@ -1451,17 +1451,6 @@
     return rep->subsref (type, idx, nargout);
 }
 
-octave_value_list
-octave_value::subsref (const std::string& type,
-                       const std::list<octave_value_list>& idx, int nargout,
-                       const std::list<octave_lvalue> *lvalue_list)
-{
-  if (lvalue_list)
-    return rep->subsref (type, idx, nargout, lvalue_list);
-  else
-    return subsref (type, idx, nargout);
-}
-
 octave_value
 octave_value::next_subsref (const std::string& type,
                             const std::list<octave_value_list>& idx,
@@ -1494,23 +1483,6 @@
     return *this;
 }
 
-octave_value_list
-octave_value::next_subsref (int nargout, const std::string& type,
-                            const std::list<octave_value_list>& idx,
-                            const std::list<octave_lvalue> *lvalue_list,
-                            size_t skip)
-{
-  if (idx.size () > skip)
-    {
-      std::list<octave_value_list> new_idx (idx);
-      for (size_t i = 0; i < skip; i++)
-        new_idx.erase (new_idx.begin ());
-      return subsref (type.substr (skip), new_idx, nargout, lvalue_list);
-    }
-  else
-    return *this;
-}
-
 octave_value
 octave_value::next_subsref (bool auto_add, const std::string& type,
                             const std::list<octave_value_list>& idx,
@@ -1533,13 +1505,6 @@
   return rep->do_multi_index_op (nargout, idx);
 }
 
-octave_value_list
-octave_value::do_multi_index_op (int nargout, const octave_value_list& idx,
-                                 const std::list<octave_lvalue> *lvalue_list)
-{
-  return rep->do_multi_index_op (nargout, idx, lvalue_list);
-}
-
 octave_value
 octave_value::subsasgn (const std::string& type,
                         const std::list<octave_value_list>& idx,
--- a/libinterp/octave-value/ov.h	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/octave-value/ov.h	Wed May 10 11:09:52 2017 -0400
@@ -431,11 +431,6 @@
                              const std::list<octave_value_list>& idx,
                              int nargout);
 
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx,
-                             int nargout,
-                             const std::list<octave_lvalue> *lvalue_list);
-
   octave_value next_subsref (const std::string& type, const
                              std::list<octave_value_list>& idx,
                              size_t skip = 1);
@@ -445,12 +440,6 @@
                                   std::list<octave_value_list>& idx,
                                   size_t skip = 1);
 
-  octave_value_list next_subsref (int nargout,
-                                  const std::string& type, const
-                                  std::list<octave_value_list>& idx,
-                                  const std::list<octave_lvalue> *lvalue_list,
-                                  size_t skip = 1);
-
   octave_value next_subsref (bool auto_add, const std::string& type, const
                              std::list<octave_value_list>& idx,
                              size_t skip = 1);
@@ -462,10 +451,6 @@
   octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& idx);
 
-  octave_value_list
-  do_multi_index_op (int nargout, const octave_value_list& idx,
-                     const std::list<octave_lvalue> *lvalue_list);
-
   octave_value subsasgn (const std::string& type,
                          const std::list<octave_value_list>& idx,
                          const octave_value& rhs);
--- a/libinterp/parse-tree/pt-arg-list.cc	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/parse-tree/pt-arg-list.cc	Wed May 10 11:09:52 2017 -0400
@@ -31,7 +31,6 @@
 
 #include "defun.h"
 #include "error.h"
-#include "oct-lvalue.h"
 #include "ovl.h"
 #include "ov.h"
 #include "ov-usr-fcn.h"
@@ -262,17 +261,6 @@
     return args;
   }
 
-  std::list<octave_lvalue>
-  tree_argument_list::lvalue_list (tree_evaluator *tw)
-  {
-    std::list<octave_lvalue> retval;
-
-    for (tree_expression *elt : *this)
-      retval.push_back (elt->lvalue (tw));
-
-    return retval;
-  }
-
   string_vector
   tree_argument_list::get_arg_names (void) const
   {
--- a/libinterp/parse-tree/pt-arg-list.h	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/parse-tree/pt-arg-list.h	Wed May 10 11:09:52 2017 -0400
@@ -28,7 +28,6 @@
 #include <list>
 
 class octave_value_list;
-class octave_lvalue;
 
 #include "str-vec.h"
 
@@ -93,8 +92,6 @@
     octave_value_list convert_to_const_vector (tree_evaluator *tw,
                                                const octave_value *object = nullptr);
 
-    std::list<octave_lvalue> lvalue_list (tree_evaluator *tw);
-
     string_vector get_arg_names (void) const;
 
     std::list<std::string> variable_names (void) const;
--- a/libinterp/parse-tree/pt-eval.cc	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/parse-tree/pt-eval.cc	Wed May 10 11:09:52 2017 -0400
@@ -82,8 +82,8 @@
   tree_evaluator::reset (void)
   {
     m_value_stack.clear ();
-    m_lvalue_list_stack.pop ();
-    m_nargout_stack.pop ();
+    m_lvalue_list_stack.clear ();
+    m_nargout_stack.clear ();
   }
 
   void
@@ -408,6 +408,43 @@
                                     || statement_context == script));
   }
 
+  Matrix
+  tree_evaluator::ignored_fcn_outputs (void) const
+  {
+    Matrix retval;
+
+    if (m_lvalue_list_stack.empty ())
+      return retval;
+
+    //    std::cerr << "lvalue_list_stack size: "
+    //              << m_lvalue_list_stack.size () << std::endl;
+
+    const std::list<octave_lvalue> *lvalue_list = m_lvalue_list_stack.top ();
+
+    octave_idx_type nbh = 0;
+
+    for (const auto& lval : *lvalue_list)
+      nbh += lval.is_black_hole ();
+
+    if (nbh > 0)
+      {
+        retval.resize (1, nbh);
+
+        octave_idx_type k = 0;
+        octave_idx_type l = 0;
+
+        for (const auto& lval : *lvalue_list)
+          {
+            if (lval.is_black_hole ())
+              retval(l++) = k+1;
+
+            k += lval.numel ();
+          }
+      }
+
+    return retval;
+  }
+
   octave_value
   tree_evaluator::evaluate (tree_decl_elt *elt)
   {
@@ -942,14 +979,7 @@
         if (fcn && ! (expr.is_postfix_indexed ()
                       && fcn->is_postfix_index_handled (expr.postfix_index ())))
           {
-            octave_value_list tmp_args;
-
-            const std::list<octave_lvalue> *lvalue_list
-              = m_lvalue_list_stack.top ();
-
-            retval = (lvalue_list
-                      ? val.do_multi_index_op (nargout, tmp_args, lvalue_list)
-                      : val.do_multi_index_op (nargout, tmp_args));
+            retval = val.do_multi_index_op (nargout, octave_value_list ());
           }
         else
           {
@@ -1230,12 +1260,9 @@
         p_dyn_field++;
       }
 
-    const std::list<octave_lvalue> *lvalue_list = m_lvalue_list_stack.top ();
-
     try
       {
-        retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout,
-                              lvalue_list);
+        retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout);
       }
     catch (octave::index_exception& e)  // range problems, bad index type, etc.
       {
@@ -1252,10 +1279,7 @@
           {
             octave_value_list empty_args;
 
-            retval = (lvalue_list
-                      ? val.do_multi_index_op (nargout, empty_args,
-                                               lvalue_list)
-                      : val.do_multi_index_op (nargout, empty_args));
+            retval = val.do_multi_index_op (nargout, empty_args);
           }
       }
 
@@ -1520,9 +1544,16 @@
 
     if (rhs)
       {
+        unwind_protect frame;
+
         tree_argument_list *lhs = expr.left_hand_side ();
 
-        std::list<octave_lvalue> lvalue_list = lhs->lvalue_list (this);
+        std::list<octave_lvalue> lvalue_list = make_lvalue_list (lhs);
+
+        m_lvalue_list_stack.push (&lvalue_list);
+
+        frame.add_method (m_lvalue_list_stack,
+                          &value_stack<const std::list<octave_lvalue>*>::pop);
 
         octave_idx_type n_out = 0;
 
@@ -1530,7 +1561,7 @@
           n_out += lval.numel ();
 
         // The following trick is used to keep rhs_val constant.
-        const octave_value_list rhs_val1 = evaluate_n (rhs, n_out, &lvalue_list);
+        const octave_value_list rhs_val1 = evaluate_n (rhs, n_out);
         const octave_value_list rhs_val = (rhs_val1.length () == 1
                                            && rhs_val1(0).is_cs_list ()
                                            ? rhs_val1(0).list_value ()
@@ -1869,8 +1900,18 @@
 
         try
           {
+            octave::unwind_protect frame;
+
             octave_lvalue ult = lhs->lvalue (this);
 
+            std::list<octave_lvalue> lvalue_list;
+            lvalue_list.push_back (ult);
+
+            m_lvalue_list_stack.push (&lvalue_list);
+
+            frame.add_method (m_lvalue_list_stack,
+                              &value_stack<const std::list<octave_lvalue>*>::pop);
+
             if (ult.numel () != 1)
               err_nonbraced_cs_list_assignment ();
 
@@ -2467,6 +2508,17 @@
 
     return expr_value;
   }
+
+  std::list<octave_lvalue>
+  tree_evaluator::make_lvalue_list (tree_argument_list *lhs)
+  {
+    std::list<octave_lvalue> retval;
+
+    for (tree_expression *elt : *lhs)
+      retval.push_back (elt->lvalue (this));
+
+    return retval;
+  }
 }
 
 DEFUN (max_recursion_depth, args, nargout,
--- a/libinterp/parse-tree/pt-eval.h	Wed May 10 15:04:28 2017 +0200
+++ b/libinterp/parse-tree/pt-eval.h	Wed May 10 11:09:52 2017 -0400
@@ -62,7 +62,12 @@
 
       void push (const T& val) { m_stack.push (val); }
 
-      T pop (void)
+      void pop (void)
+      {
+        m_stack.pop ();
+      }
+
+      T val_pop (void)
       {
         T retval = m_stack.top ();
         m_stack.pop ();
@@ -74,6 +79,16 @@
         return m_stack.top ();
       }
 
+      size_t size (void) const
+      {
+        return m_stack.size ();
+      }
+
+      bool empty (void) const
+      {
+        return m_stack.empty ();
+      }
+
       void clear (void)
       {
         while (! m_stack.empty ())
@@ -225,35 +240,35 @@
     // TRUE means we are evaluating some kind of looping construct.
     static bool in_loop_command;
 
-    octave_value evaluate (tree_expression *expr, int nargout = 1,
-                           const std::list<octave_lvalue> *lvalue_list = nullptr)
+    Matrix ignored_fcn_outputs (void) const;
+
+    const std::list<octave_lvalue> * lvalue_list (void)
+    {
+      return m_lvalue_list_stack.empty () ? 0 : m_lvalue_list_stack.top ();
+    }
+
+    octave_value evaluate (tree_expression *expr, int nargout = 1)
     {
       m_nargout_stack.push (nargout);
-      m_lvalue_list_stack.push (lvalue_list);
 
       expr->accept (*this);
 
       m_nargout_stack.pop ();
-      m_lvalue_list_stack.pop ();
 
-      octave_value_list tmp = m_value_stack.pop ();
+      octave_value_list tmp = m_value_stack.val_pop ();
 
       return tmp.empty () ? octave_value () : tmp(0);
     }
 
-    octave_value_list
-    evaluate_n (tree_expression *expr, int nargout = 1,
-                const std::list<octave_lvalue> *lvalue_list = nullptr)
+    octave_value_list evaluate_n (tree_expression *expr, int nargout = 1)
     {
       m_nargout_stack.push (nargout);
-      m_lvalue_list_stack.push (lvalue_list);
 
       expr->accept (*this);
 
       m_nargout_stack.pop ();
-      m_lvalue_list_stack.pop ();
 
-      return m_value_stack.pop ();
+      return m_value_stack.val_pop ();
     }
 
     octave_value evaluate (tree_decl_elt *);
@@ -289,6 +304,8 @@
 
     bool is_logically_true (tree_expression *expr, const char *warn_for);
 
+    std::list<octave_lvalue> make_lvalue_list (tree_argument_list *);
+
     value_stack<octave_value_list> m_value_stack;
 
     value_stack<const std::list<octave_lvalue>*> m_lvalue_list_stack;