summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pp_ctl.c8
-rw-r--r--t/re/reg_eval_scope.t69
2 files changed, 73 insertions, 4 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index aae200f74d..f08e3764c2 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -1438,8 +1438,14 @@ S_dopoptosub_at(pTHX_ const PERL_CONTEXT *cxstk, I32 startingblock)
switch (CxTYPE(cx)) {
default:
continue;
- case CXt_EVAL:
case CXt_SUB:
+ /* in sub foo { /(?{...})/ }, foo ends up on the CX stack
+ * twice; the first for the normal foo() call, and the second
+ * for a faked up re-entry into the sub to execute the
+ * code block. Hide this faked entry from the world. */
+ if (cx->cx_type & CXp_SUB_RE_FAKE)
+ continue;
+ case CXt_EVAL:
case CXt_FORMAT:
DEBUG_l( Perl_deb(aTHX_ "(dopoptosub_at(): found sub at cx=%ld)\n", (long)i));
return i;
diff --git a/t/re/reg_eval_scope.t b/t/re/reg_eval_scope.t
index 46b9bb27e1..80eeb8aa67 100644
--- a/t/re/reg_eval_scope.t
+++ b/t/re/reg_eval_scope.t
@@ -9,7 +9,7 @@ BEGIN {
skip_all_if_miniperl("no dynamic loading on miniperl, no re");
}
-plan 34;
+plan 45;
fresh_perl_is <<'CODE', '781745', {}, '(?{}) has its own lexical scope';
my $x = 7; my $a = 4; my $b = 5;
@@ -131,11 +131,11 @@ CODE
fresh_perl_is <<'CODE',
my $a=4; my $b=5;
- sub f { print ((caller(0))[3], "-", (caller(1))[3], "\n") };
+ sub f { print ((caller(0))[3], "-", (caller(1))[3], "-\n") };
"a" =~ /(?{f()})a/;
print $a,$b;
CODE
- "main::f-(unknown)\n45",
+ "main::f--\n45",
{ stderr => 1 }, 'sub f {caller} /(?{f()})/';
@@ -282,3 +282,66 @@ pass "undef *_ in a re-eval does not cause a double free";
$l = __LINE__; "4" =~ /^$c/x or warn "foo";
like($w, qr/foo.+line $l/, 'curcop 4');
}
+
+# [perl #113928] caller behaving unexpectedly in re-evals
+#
+# /(?{...})/ should be in the same caller scope as the surrounding code;
+# qr/(?{...})/ should be in an anon sub
+
+{
+
+ my $l;
+
+ sub callers {
+ my @c;
+ my $stack = '';
+ my $i = 1;
+ while (@c = caller($i++)) {
+ $stack .= "($c[3]:" . ($c[2] - $l) . ')';
+ }
+ $stack;
+ }
+
+ $l = __LINE__;
+ my $c;
+ is (callers(), '', 'callers() null');
+ "" =~ /(?{ $c = callers() })/;
+ is ($c, '', 'callers() //');
+
+ $l = __LINE__;
+ sub m1 { "" =~ /(?{ $c = callers() })/; }
+ m1();
+ is ($c, '(main::m1:2)', 'callers() m1');
+
+ $l = __LINE__;
+ my $r1 = qr/(?{ $c = callers() })/;
+ "" =~ /$r1/;
+ is ($c, '(main::__ANON__:2)', 'callers() r1');
+
+ $l = __LINE__;
+ sub r1 { "" =~ /$r1/; }
+ r1();
+ is ($c, '(main::__ANON__:1)(main::r1:2)', 'callers() r1/r1');
+
+ $l = __LINE__;
+ sub c2 { $c = callers() }
+ my $r2 = qr/(?{ c2 })/;
+ "" =~ /$r2/;
+ is ($c, '(main::c2:2)(main::__ANON__:3)', 'callers() r2/c2');
+ sub r2 { "" =~ /$r2/; }
+ r2();
+ is ($c, '(main::c2:2)(main::__ANON__:5)(main::r2:6)', 'callers() r2/r2/c2');
+
+ $l = __LINE__;
+ sub c3 { $c = callers() }
+ my $r3 = qr/(?{ c3 })/;
+ my $c1;
+ "ABC" =~ /A(?{ $c1 = callers() })B${r3}C/;
+ is ($c, '(main::c3:2)(main::__ANON__:4)', 'callers() r3/c3');
+ is ($c1,'', 'callers() r3/c3 part 2');
+ sub r3 { "ABC" =~ /A(?{ $c1 = callers() })B${r3}C/; }
+ r3();
+ is ($c, '(main::c3:2)(main::__ANON__:7)(main::r3:8)', 'callers() r3/r3/c3');
+ is ($c1,'(main::r3:8)', 'callers() r3/r3/c3 part 2');
+
+}