summaryrefslogtreecommitdiff
path: root/cop.h
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-07-09 19:18:45 -0700
committerFather Chrysostomos <sprout@cpan.org>2011-07-09 19:19:51 -0700
commit777d9014444bb88a98ccd6c09ebb520cdc4c0d8b (patch)
treeadd55b04929f0bc1462315c6aa167b4bfa2c641e /cop.h
parentfe57f3b7598666107c5e6e9c9ffd844da47ea527 (diff)
downloadperl-777d9014444bb88a98ccd6c09ebb520cdc4c0d8b.tar.gz
Propagate (non-)lvalue context through nested calls
Before this commit, this code would fail: $foo = "foo"; sub foo :lvalue{ return index "foo","o" } sub bar :lvalue { foo } $x = bar; (It would fail for ‘return $]’ as well. Whether it’s a PADTMP or a read-only scalar makes no difference.) foo would think it was being called in true lvalue context, because the entersub op that called it (in bar) was marked that way, bar being an lvalue sub as well. The PUSHSUB macro in cop.h needed to be modified to account for dynamic, or indetermine, context (i.e., indeterminable at compile time). This happens when an entersub op is an argument to return or the last statement in a subroutine. In those cases it has to propa- gate the context from the caller. So what we now do is this: Both lvalue and in-args flags are turned on for an entersub op when op_lvalue is called with OP_LEAVESUBLV as the type. Then PUSHSUB copies into the context stack only those flags that are set both on the current entersub op and in the context stack for the previous sub call.
Diffstat (limited to 'cop.h')
-rw-r--r--cop.h11
1 files changed, 10 insertions, 1 deletions
diff --git a/cop.h b/cop.h
index 82eee29fa9..d261edf13b 100644
--- a/cop.h
+++ b/cop.h
@@ -633,9 +633,18 @@ struct block_format {
#define PUSHSUB(cx) \
+ { \
+ /* If the context is indeterminate, then only the lvalue */ \
+ /* flags that the caller also has are applicable. */ \
+ U8 phlags = \
+ (PL_op->op_flags & OPf_WANT) \
+ ? OPpENTERSUB_LVAL_MASK \
+ : !(PL_op->op_private & OPpENTERSUB_LVAL_MASK) \
+ ? 0 : was_lvalue_sub(); \
PUSHSUB_BASE(cx) \
cx->blk_u16 = PL_op->op_private & \
- (OPpLVAL_INTRO|OPpENTERSUB_INARGS|OPpENTERSUB_DEREF);
+ (phlags|OPpENTERSUB_DEREF); \
+ }
/* variant for use by OP_DBSTATE, where op_private holds hint bits */
#define PUSHSUB_DB(cx) \