This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Adjust substr offsets when using, not when creating, lvalue
authorFather Chrysostomos <sprout@cpan.org>
Sun, 4 Dec 2011 18:47:40 +0000 (10:47 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 4 Dec 2011 18:50:48 +0000 (10:50 -0800)
commit83f78d1a27d5727dabfc8bcc2b961cb405b831e9
tree77674fd3efedbd14bec2f2ffa6176678ff28fa67
parent7ba26d48121ff365601a73eefc7798693a3a9118
Adjust substr offsets when using, not when creating, lvalue

When substr() occurs in potential lvalue context, the offsets are
adjusted to the current string (negative being converted to positive,
lengths reaching beyond the end of the string being shortened, etc.)
as soon as the special lvalue to be returned is created.

When that lvalue is assigned to, the original scalar is stringified
once more.

That implementation results in two bugs:

1) Fetch is called twice in a simple substr() assignment (except in
void context, due to the special optimisation of commit 24fcb59fc).

2) These two calls are not equivalent:

$SIG{__WARN__} = sub { warn "w ",shift};
sub myprint { print @_; $_[0] = 1 }
print substr("", 2);
myprint substr("", 2);

The second one dies.  The first one only warns.  That’s mean.  The
error is also wrong, sometimes, if the original string is going to get
longer before the substr lvalue is actually used.

The behaviour of \substr($str, -1) if $str changes length is com-
pletely undocumented.  Before 5.10, it was documented as being unreli-
able and subject to change.

What this commit does is make the lvalue returned by substr remember
the original arguments and only adjust the offsets when the assign-
ment happens.

This means that the following now prints z, instead of xyz (which is
actually what I would expect):

$str = "a";
$substr = \substr($str,-1);
$str = "xyz";
print $substr;
dump.c
embed.fnc
embed.h
mg.c
pp.c
proto.h
sv.h
t/op/substr.t