summaryrefslogtreecommitdiff
path: root/pp_ctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'pp_ctl.c')
-rw-r--r--pp_ctl.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index d34b8d2393..443f4176ac 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -2988,6 +2988,7 @@ PP(pp_goto)
const SSize_t items = arg ? AvFILL(arg) + 1 : 0;
const bool m = arg ? cBOOL(SvRMAGICAL(arg)) : 0;
SV** mark;
+ UNOP fake_goto_op;
ENTER;
SAVETMPS;
@@ -3024,6 +3025,20 @@ PP(pp_goto)
PL_comppad = cx->blk_sub.prevcomppad;
PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL;
+ /* Make a temporary a copy of the current GOTO op on the C
+ * stack, but with a modified gimme (we can't modify the
+ * real GOTO op as that's not thread-safe). This allows XS
+ * users of GIMME_V to get the correct calling context,
+ * even though there is no longer a CXt_SUB frame to
+ * provide that information.
+ */
+ Copy(PL_op, &fake_goto_op, 1, UNOP);
+ fake_goto_op.op_flags =
+ (fake_goto_op.op_flags & ~OPf_WANT)
+ | (cx->blk_gimme & G_WANT);
+ SAVEOP();
+ PL_op = (OP*)&fake_goto_op;
+
/* XS subs don't have a CXt_SUB, so pop it;
* this is a cx_popblock(), less all the stuff we already did
* for cx_topblock() earlier */