# HG changeset patch # User Fernando Alvarruiz # Date 1681547857 -7200 # Node ID 554a932fc6d0cfd311fa8fc2bc6aa2059595e79b # Parent 818698c4f29684a4029d36c57e6785d2767a04c9 Fix nargout when calling class subsref method (bug #63841) * libinterp/octave-value/ov-class.cc (octave_class::subsref), libinterp/octave-value/ov-classdef.cc (octave_classdef::subsref): Do not change value of nargout if it is positive. Return a cs-list only if the caller accepts more than one output. * libinterp/parse-tree/pt-eval.cc (tree_evaluator::convert_to_const_vector): Use nargout=-1 to indicate unknown number of output arguments. (tree_evaluator::execute_builtin_function, tree_evaluator::execute_mex_function, tree_evaluator::execute_user_function): if nargout negative, use argout=1 * libinterp/parse-tree/pt-tm-const.cc (tm_row_const::init), libinterp/parse-tree/pt-binop.cc (tree_binary_expression::evaluate), libinterp/parse-tree/pt-cbinop.cc (tree_compound_binary_expression::evaluate), libinterp/parse-tree/pt-unop.cc (tree_prefix_expression::evaluate, tree_postfix_expression::evaluate): Use nargout=-1 to indicate unknown number of output arguments. diff -r 818698c4f296 -r 554a932fc6d0 libinterp/octave-value/ov-class.cc --- a/libinterp/octave-value/ov-class.cc Fri Oct 13 17:56:34 2023 +0200 +++ b/libinterp/octave-value/ov-class.cc Sat Apr 15 10:37:37 2023 +0200 @@ -465,32 +465,44 @@ m_count++; args(0) = octave_value (this); - // FIXME: for Matlab compatibility, let us attempt to set up a proper - // value for nargout at least in the simple case where the + // If the number of output arguments is unknown, attempt to set up + // a proper value for nargout at least in the simple case where the // cs-list-type expression - i.e., {} or ().x, is the leading one. - // Note that Octave does not actually need this, since it will - // be able to properly react to varargout a posteriori. - bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{' - || (type.length () > 1 && type[0] == '(' - && type[1] == '.')); - - int true_nargout = nargout; - - if (maybe_cs_list_query) + if (nargout <= 0) { - // Set up a proper nargout for the subsref call by calling numel. - octave_value_list tmp; - if (type[0] != '.') tmp = idx.front (); - true_nargout = xnumel (tmp); + bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{' + || (type.length () > 1 && type[0] == '(' + && type[1] == '.')); + + if (maybe_cs_list_query) + { + // Set up a proper nargout for the subsref call by calling numel. + octave_value_list tmp; + int nout; + if (type[0] != '.') tmp = idx.front (); + nout = xnumel (tmp); + if (nargout != 0 || nout > 1) + nargout = nout; + } + else if (nargout < 0) + nargout = 1; } - retval = interp.feval (meth.function_value (), args, true_nargout); - - // Since we're handling subsref, if the list has more than one - // element, return it as a comma-separated list so that we can - // pass it to the evaluator - if (retval.length () > 1) - retval = octave_value (retval); + retval = interp.feval (meth.function_value (), args, nargout); + + // Since we're handling subsref, if the list has more than one element + // and the caller to subsref accepts more that one output, return + // the elements as a comma-separated list so that we can pass it to the + // evaluator + if (retval.length () > 1 && (nargout < 0 || nargout >1)) + { + if (nargout <= 0 || nargout>=retval.length()) + // Take the whole list + retval = octave_value (retval); + else + // Take nargout elements of the list + retval = octave_value(retval.slice(0,nargout)); + } } else { diff -r 818698c4f296 -r 554a932fc6d0 libinterp/octave-value/ov-classdef.cc --- a/libinterp/octave-value/ov-classdef.cc Fri Oct 13 17:56:34 2023 +0200 +++ b/libinterp/octave-value/ov-classdef.cc Sat Apr 15 10:37:37 2023 +0200 @@ -91,28 +91,44 @@ m_count++; args(0) = octave_value (this); - // Attempt to set up a proper value for nargout at least in the - // simple case where the cs-list-type expression - i.e., {} or - // ().x, is the leading one. - bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{' - || (type.length () > 1 && type[0] == '(' - && type[1] == '.')); + // If the number of output arguments is unknown, attempt to set up + // a proper value for nargout at least in the simple case where the + // cs-list-type expression - i.e., {} or ().x, is the leading one. + if (nargout <= 0) + { + bool maybe_cs_list_query = (type[0] == '.' || type[0] == '{' + || (type.length () > 1 && type[0] == '(' + && type[1] == '.')); - if (maybe_cs_list_query) - { - // Set up a proper nargout for the subsref call by calling numel. - octave_value_list tmp; - if (type[0] != '.') tmp = idx.front (); - nargout = xnumel (tmp); + if (maybe_cs_list_query) + { + // Set up a proper nargout for the subsref call by calling numel. + octave_value_list tmp; + int nout; + if (type[0] != '.') tmp = idx.front (); + nout = xnumel (tmp); + if (nargout != 0 || nout > 1) + nargout = nout; + } + else if (nargout < 0) + nargout = 1; } retval = meth.execute (args, nargout, true, "subsref"); - // Since we're handling subsref, if the list has more than one - // element, return it as a comma-separated list so that we can - // pass it to the evaluator - if (retval.length () > 1) - retval = octave_value (retval); + // Since we're handling subsref, if the list has more than one element + // and the caller to subsref accepts more that one output, return + // the elements as a comma-separated list so that we can pass it to the + // evaluator + if (retval.length () > 1 && (nargout < 0 || nargout >1)) + { + if (nargout <= 0 || nargout>=retval.length()) + // Take the whole list + retval = octave_value (retval); + else + // Take nargout elements of the list + retval = octave_value(retval.slice(0,nargout)); + } return retval; } diff -r 818698c4f296 -r 554a932fc6d0 libinterp/parse-tree/pt-binop.cc --- a/libinterp/parse-tree/pt-binop.cc Fri Oct 13 17:56:34 2023 +0200 +++ b/libinterp/parse-tree/pt-binop.cc Sat Apr 15 10:37:37 2023 +0200 @@ -71,11 +71,13 @@ { if (m_lhs) { - octave_value a = m_lhs->evaluate (tw); + // Evaluate with unknown number of output arguments + octave_value a = m_lhs->evaluate (tw, -1); if (a.is_defined () && m_rhs) { - octave_value b = m_rhs->evaluate (tw); + // Evaluate with unknown number of output arguments + octave_value b = m_rhs->evaluate (tw, -1); if (b.is_defined ()) { diff -r 818698c4f296 -r 554a932fc6d0 libinterp/parse-tree/pt-cbinop.cc --- a/libinterp/parse-tree/pt-cbinop.cc Fri Oct 13 17:56:34 2023 +0200 +++ b/libinterp/parse-tree/pt-cbinop.cc Sat Apr 15 10:37:37 2023 +0200 @@ -42,11 +42,13 @@ if (m_lhs) { - octave_value a = m_lhs->evaluate (tw); + // Evaluate with unknown number of output arguments + octave_value a = m_lhs->evaluate (tw, -1); if (a.is_defined () && m_rhs) { - octave_value b = m_rhs->evaluate (tw); + // Evaluate with unknown number of output arguments + octave_value b = m_rhs->evaluate (tw, -1); if (b.is_defined ()) { diff -r 818698c4f296 -r 554a932fc6d0 libinterp/parse-tree/pt-eval.cc --- a/libinterp/parse-tree/pt-eval.cc Fri Oct 13 17:56:34 2023 +0200 +++ b/libinterp/parse-tree/pt-eval.cc Sat Apr 15 10:37:37 2023 +0200 @@ -2306,7 +2306,8 @@ if (! elt) break; - octave_value tmp = elt->evaluate (*this); + // Evaluate with unknown number of output arguments + octave_value tmp = elt->evaluate (*this, -1); if (tmp.is_cs_list ()) { @@ -3412,6 +3413,11 @@ octave_builtin::fcn fcn = builtin_function.function (); + // If number of outputs unknown (and this is not a complete statement), + // pass nargout=1 to the function being called + if (nargout < 0) + nargout = 1; + if (fcn) retval = (*fcn) (args, nargout); else @@ -3455,6 +3461,11 @@ profiler::enter block (m_profiler, mex_function); + // If number of outputs unknown (and this is not a complete statement), + // pass nargout=1 to the function being called + if (nargout < 0) + nargout = 1; + retval = call_mex (mex_function, args, nargout); return retval; @@ -3529,6 +3540,11 @@ int nargin = args.length (); + // If number of outputs unknown (and this is not a complete statement), + // pass nargout=1 to the function being called + if (nargout < 0) + nargout = 1; + if (user_function.is_classdef_constructor ()) { if (nargin > 0) diff -r 818698c4f296 -r 554a932fc6d0 libinterp/parse-tree/pt-tm-const.cc --- a/libinterp/parse-tree/pt-tm-const.cc Fri Oct 13 17:56:34 2023 +0200 +++ b/libinterp/parse-tree/pt-tm-const.cc Sat Apr 15 10:37:37 2023 +0200 @@ -182,7 +182,8 @@ { octave_quit (); - octave_value tmp = elt->evaluate (tw); + // Evaluate with unknown number of output arguments + octave_value tmp = elt->evaluate (tw, -1); if (tmp.is_undefined ()) error ("undefined element in matrix list"); diff -r 818698c4f296 -r 554a932fc6d0 libinterp/parse-tree/pt-unop.cc --- a/libinterp/parse-tree/pt-unop.cc Fri Oct 13 17:56:34 2023 +0200 +++ b/libinterp/parse-tree/pt-unop.cc Sat Apr 15 10:37:37 2023 +0200 @@ -77,7 +77,8 @@ } else { - octave_value op_val = m_op->evaluate (tw); + // Evaluate with unknown number of output arguments + octave_value op_val = m_op->evaluate (tw, -1); if (op_val.is_defined ()) { @@ -138,7 +139,8 @@ } else { - octave_value op_val = m_op->evaluate (tw); + // Evaluate with unknown number of output arguments + octave_value op_val = m_op->evaluate (tw, -1); if (op_val.is_defined ()) {