summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-05-31 17:09:15 -0700
committerFather Chrysostomos <sprout@cpan.org>2011-05-31 17:09:15 -0700
commitfd6c41ce5607a262d2124271d289aa2a0213c049 (patch)
tree491ece948e641e2b9584450ac33cf7417078e58c /pp_hot.c
parentc73030b8a71ef564254d3a858775de115ce7f6b5 (diff)
downloadperl-fd6c41ce5607a262d2124271d289aa2a0213c049.tar.gz
Allow lvalue subs to return TEMPs
This is perhaps not ideal, but it fixes (or allows to be fixed) seve- ral bugs. I was hoping that the cases that this perhaps erroneously allows through would fall back to the warning I added in commit 8fe85e3, but, unfortunately, in all these cases the refcount is greater than 1 when pp_sassign is reached. To be less vague: ‘foo() = 3’ warns if foo() returns a TEMP with no set-magic and a refcount of 1 (meaning it will be freed shortly). But truly temporary values returned by pure-Perl lvalue subs have a refer- ence count of at least 2, and as many entries on the mortals stack. I cannot distinguish between truly temporary values and those that are but nominally temporary (marked TEMP because the refcount will go down, but not to zero) by checking for a refcount <= 2 in pp_sassign, because this example returns with a refcount of 2: +sub :lvalue { return delete($_[0]), $x }->($x) = 3; # returns a TEMP There’s no logical reason why that shouldn’t work, if this does: +sub :lvalue { return foo(), $x }->($x) = 3; # not TEMP as they are conceptually identical. The advantages to this change: • The delete example above will work. • It allows XS lvalue subs that return TEMPs to work in the debugger [perl #71172], restoring the bug fix that b724cc1 implemented but c73030b reverted. • It makes these three cases identical, as they should be. Note that only two of them return TEMPs: +sub :lvalue { return shift }->($x) = 3; +sub :lvalue { \@_; return shift }->($x) = 3; # returns a TEMP +sub :lvalue { return delete $_[0] }->($x) = 3; # returns a TEMP So I think the advantages outweigh the disadvantages.
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c6
1 files changed, 2 insertions, 4 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 3bafefb79c..2525a26d39 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -2725,9 +2725,7 @@ PP(pp_leavesublv)
MARK = newsp + 1;
EXTEND_MORTAL(1);
if (MARK == SP) {
- /* Temporaries are bad unless they happen to have set magic
- * attached, such as the elements of a tied hash or array */
- if ((SvFLAGS(TOPs) & (SVs_TEMP | SVs_PADTMP) ||
+ if ((SvPADTMP(TOPs) ||
(SvFLAGS(TOPs) & (SVf_READONLY | SVf_FAKE))
== SVf_READONLY
) &&
@@ -2762,7 +2760,7 @@ PP(pp_leavesublv)
EXTEND_MORTAL(SP - newsp);
for (mark = newsp + 1; mark <= SP; mark++) {
if (*mark != &PL_sv_undef
- && (SvFLAGS(*mark) & (SVs_TEMP | SVs_PADTMP)
+ && (SvPADTMP(*mark)
|| (SvFLAGS(*mark) & (SVf_READONLY|SVf_FAKE))
== SVf_READONLY
)