dcb3b7
From 0a1ddbeaeeea3c690c2408bd4c3a61c05cb9695f Mon Sep 17 00:00:00 2001
dcb3b7
From: Zefram <zefram@fysh.org>
dcb3b7
Date: Mon, 23 Jan 2017 02:25:50 +0000
dcb3b7
Subject: [PATCH] permit goto at top level of multicalled sub
dcb3b7
MIME-Version: 1.0
dcb3b7
Content-Type: text/plain; charset=UTF-8
dcb3b7
Content-Transfer-Encoding: 8bit
dcb3b7
dcb3b7
Petr Písař: Ported to 5.24.1:
dcb3b7
dcb3b7
commit 3c157b3cf0631c69ffa5aa2d55b9199bf93b22a9
dcb3b7
Author: Zefram <zefram@fysh.org>
dcb3b7
Date:   Mon Jan 23 02:25:50 2017 +0000
dcb3b7
dcb3b7
    permit goto at top level of multicalled sub
dcb3b7
dcb3b7
    A multicalled sub is reckoned to be a pseudo block, out of which it is
dcb3b7
    not permissible to goto.  However, the test for a pseudo block was being
dcb3b7
    applied too early, preventing not just escape from a multicalled sub but
dcb3b7
    also a goto at the top level within the sub.  This is a bug similar, but
dcb3b7
    not identical, to [perl #113938].  Now the test is deferred, permitting
dcb3b7
    goto at the sub's top level but still forbidding goto out of it.
dcb3b7
dcb3b7
Signed-off-by: Petr Písař <ppisar@redhat.com>
dcb3b7
---
dcb3b7
 pp_ctl.c    | 11 ++++++-----
dcb3b7
 t/op/goto.t | 11 ++++++++++-
dcb3b7
 2 files changed, 16 insertions(+), 6 deletions(-)
dcb3b7
dcb3b7
diff --git a/pp_ctl.c b/pp_ctl.c
dcb3b7
index e859e01..a1fc2f4 100644
dcb3b7
--- a/pp_ctl.c
dcb3b7
+++ b/pp_ctl.c
dcb3b7
@@ -2921,6 +2921,7 @@ PP(pp_goto)
dcb3b7
 	OP *gotoprobe = NULL;
dcb3b7
 	bool leaving_eval = FALSE;
dcb3b7
 	bool in_block = FALSE;
dcb3b7
+	bool pseudo_block = FALSE;
dcb3b7
 	PERL_CONTEXT *last_eval_cx = NULL;
dcb3b7
 
dcb3b7
 	/* find label */
dcb3b7
@@ -2959,11 +2960,9 @@ PP(pp_goto)
dcb3b7
 		    gotoprobe = PL_main_root;
dcb3b7
 		break;
dcb3b7
 	    case CXt_SUB:
dcb3b7
-		if (CvDEPTH(cx->blk_sub.cv) && !CxMULTICALL(cx)) {
dcb3b7
-		    gotoprobe = CvROOT(cx->blk_sub.cv);
dcb3b7
-		    break;
dcb3b7
-		}
dcb3b7
-		/* FALLTHROUGH */
dcb3b7
+		gotoprobe = CvROOT(cx->blk_sub.cv);
dcb3b7
+		pseudo_block = cBOOL(CxMULTICALL(cx));
dcb3b7
+		break;
dcb3b7
 	    case CXt_FORMAT:
dcb3b7
 	    case CXt_NULL:
dcb3b7
 		DIE(aTHX_ "Can't \"goto\" out of a pseudo block");
dcb3b7
@@ -2992,6 +2991,8 @@ PP(pp_goto)
dcb3b7
 			break;
dcb3b7
 		}
dcb3b7
 	    }
dcb3b7
+	    if (pseudo_block)
dcb3b7
+		DIE(aTHX_ "Can't \"goto\" out of a pseudo block");
dcb3b7
 	    PL_lastgotoprobe = gotoprobe;
dcb3b7
 	}
dcb3b7
 	if (!retop)
dcb3b7
diff --git a/t/op/goto.t b/t/op/goto.t
dcb3b7
index aa2f24f..07bd6fb 100644
dcb3b7
--- a/t/op/goto.t
dcb3b7
+++ b/t/op/goto.t
dcb3b7
@@ -10,7 +10,7 @@ BEGIN {
dcb3b7
 
dcb3b7
 use warnings;
dcb3b7
 use strict;
dcb3b7
-plan tests => 98;
dcb3b7
+plan tests => 99;
dcb3b7
 our $TODO;
dcb3b7
 
dcb3b7
 my $deprecated = 0;
dcb3b7
@@ -774,3 +774,12 @@ sub FETCH     { $_[0][0] }
dcb3b7
 tie my $t, "", sub { "cluck up porridge" };
dcb3b7
 is eval { sub { goto $t }->() }//$@, 'cluck up porridge',
dcb3b7
   'tied arg returning sub ref';
dcb3b7
+
dcb3b7
+sub revnumcmp ($$) {
dcb3b7
+  goto FOO;
dcb3b7
+  die;
dcb3b7
+  FOO:
dcb3b7
+  return $_[1] <=> $_[0];
dcb3b7
+}
dcb3b7
+is eval { join(":", sort revnumcmp (9,5,1,3,7)) }, "9:7:5:3:1",
dcb3b7
+  "can goto at top level of multicalled sub";
dcb3b7
-- 
dcb3b7
2.7.4
dcb3b7