summaryrefslogtreecommitdiff
path: root/op.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2014-11-02 06:02:18 -0800
committerFather Chrysostomos <sprout@cpan.org>2014-11-13 04:49:39 -0800
commit9d391755a062145d74c79dabcfd610dda7e9c441 (patch)
treeba2f3e0f4b72be5e72d4ce4d9c2f958bc4ad20bc /op.c
parent3c37c25ad7cb92aee523edcbedcb46950479df92 (diff)
downloadperl-9d391755a062145d74c79dabcfd610dda7e9c441.tar.gz
Don’t inline sub(){ 0; return $x }
If return occurs at the end of a sub, it is optimised out of the execution, chain, so we have to look at the op tree structure to detect it.
Diffstat (limited to 'op.c')
-rw-r--r--op.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/op.c b/op.c
index 1ec729ee3b..78a4aac022 100644
--- a/op.c
+++ b/op.c
@@ -8578,7 +8578,15 @@ Perl_newATTRSUB_x(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs,
if (CvCLONE(cv)) {
assert(!CvCONST(cv));
- if (ps && !*ps && !attrs && op_const_sv(block, cv, NULL))
+ if (ps && !*ps && !attrs
+ /* Check whether this sub is a potentially inlinable closure.
+ First check for an explicit return at the end of the sub.
+ Perl_rpeep will have removed it from the execution chain,
+ yet we promise that it will prevent inlining. */
+ && block->op_type == OP_LINESEQ
+ && cLISTOPx(block)->op_last->op_type != OP_RETURN
+ /* Then search the op tree for a single lexical. */
+ && op_const_sv(block, cv, NULL))
CvCONST_on(cv);
}