This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
multideref: handle both OPpLVAL_INTRO,OPpDEREF
authorDavid Mitchell <davem@iabyn.com>
Tue, 7 Feb 2017 15:45:14 +0000 (15:45 +0000)
committerDavid Mitchell <davem@iabyn.com>
Tue, 7 Feb 2017 15:46:57 +0000 (15:46 +0000)
commit43dbb3c1592f7f9ccbe0aba64ef2684f39b673ed
tree34b7347a24582292be93cb74c15dd562a1e0a731
parentf34228d67754c62c57c3533a692e29f905d8f15a
multideref: handle both OPpLVAL_INTRO,OPpDEREF

RT #130727

In a nested dereference like $a[0]{b}[1], all but the last aelem/helem
will normally have a OPpDEREF_AV/HV flag, while the last won't have a deref
but may well have OPpLVAL_INTRO, e.g.

    local $a[0]{b}[1] = 1;

The code in S_maybe_multideref() which converts a chain of aelem/helem's
into a single mltideref op assumes this - in particular that an op can't
have both OPpLVAL_INTRO and OPpDEREF* at the same time.  However, the
following code violates that assumption:

    @{ local $a[0]{b}[1] } = 1;

In @{expr} = 1, the array is in lvalue context, which makes expr be done
in ref (autovivify) context. So the final aelem in the above expression
gets both OPpLVAL_INTRO and OPpDEREF_AV flags.

In the old days, pp_aelem (probably more by luck than design) would action
OPpLVAL_INTRO and ignore OPpDEREF_AV. This commit makes pp_multideref
behave in the same way. In particular, there's no point in autovivifying
$a[0]{b}[1] as an array ref since the local() will be undone before it
gets a change to be used.

The easiest way to achieve this is to tun off the OPpDEREF flag on the
aelem/helem op if the OPpLVAL_INTRO flag is set.
op.c
t/op/multideref.t