summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEarlopain <14981592+Earlopain@users.noreply.github.com>2026-05-13 13:52:14 +0200
committerNobuyoshi Nakada <nobu.nakada@gmail.com>2026-05-15 19:58:27 +0900
commit11de89ca1a94899535875ea594962c79713615b1 (patch)
tree4e4168068173f85498f1c7541af29568be656ab1
parent4d87d43b01dbb312eb1ff5fbbc6c9f33218d91a2 (diff)
Reject `END { next } ` as well
Followup for https://bugs.ruby-lang.org/issues/20409
-rw-r--r--parse.y32
-rw-r--r--prism/prism.c3
-rw-r--r--test/prism/errors/4.1/end_block_exit.txt5
-rw-r--r--test/prism/fixtures/3.3-4.0/end_block_exit.txt4
-rw-r--r--test/prism/fixtures/end_block_exit.txt3
-rw-r--r--test/ruby/test_ast.rb7
6 files changed, 18 insertions, 36 deletions
diff --git a/parse.y b/parse.y
index d163d2a050..ecd26acbbb 100644
--- a/parse.y
+++ b/parse.y
@@ -1659,22 +1659,7 @@ static NODE *add_block_exit(struct parser_params *p, NODE *node);
static rb_node_exits_t *init_block_exit(struct parser_params *p);
static rb_node_exits_t *allow_block_exit(struct parser_params *p);
static void restore_block_exit(struct parser_params *p, rb_node_exits_t *exits);
-static void clear_block_exit(struct parser_params *p, unsigned int error_mask);
-
-static unsigned int
-exits_mask(enum node_type t)
-{
- switch (t) {
- case NODE_BREAK:
- case NODE_NEXT:
- case NODE_REDO:
- return 1u << (t - NODE_BREAK);
- default:
- UNREACHABLE_RETURN(0);
- }
-}
-
-#define EXITS_MASK_ALL (exits_mask(NODE_BREAK)|exits_mask(NODE_NEXT)|exits_mask(NODE_REDO))
+static void clear_block_exit(struct parser_params *p, bool error);
static void
next_rescue_context(struct lex_context *next, const struct lex_context *outer, enum rescue_context def)
@@ -1692,7 +1677,7 @@ restore_defun(struct parser_params *p, rb_node_def_temp_t *temp)
p->ctxt.in_rescue = ctxt.in_rescue;
p->max_numparam = temp->save.max_numparam;
numparam_pop(p, temp->save.numparam_save);
- clear_block_exit(p, EXITS_MASK_ALL);
+ clear_block_exit(p, true);
}
static void
@@ -1849,23 +1834,20 @@ restore_block_exit(struct parser_params *p, rb_node_exits_t *exits)
}
static void
-clear_block_exit(struct parser_params *p, unsigned int error_mask)
+clear_block_exit(struct parser_params *p, bool error)
{
rb_node_exits_t *exits = p->exits;
if (!exits) return;
- if (error_mask) {
+ if (error) {
for (NODE *e = RNODE(exits); (e = RNODE_EXITS(e)->nd_chain) != 0; ) {
switch (nd_type(e)) {
case NODE_BREAK:
- if (!(error_mask & exits_mask(NODE_BREAK))) break;
yyerror1(&e->nd_loc, "Invalid break");
break;
case NODE_NEXT:
- if (!(error_mask & exits_mask(NODE_NEXT))) break;
yyerror1(&e->nd_loc, "Invalid next");
break;
case NODE_REDO:
- if (!(error_mask & exits_mask(NODE_REDO))) break;
yyerror1(&e->nd_loc, "Invalid redo");
break;
default:
@@ -3230,7 +3212,7 @@ top_stmts : none
top_stmt : stmt
{
- clear_block_exit(p, EXITS_MASK_ALL);
+ clear_block_exit(p, true);
$$ = $1;
}
| keyword_BEGIN begin_block
@@ -3370,7 +3352,7 @@ stmt : keyword_alias[kw] fitem[new] {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fit
}
| stmt[body] modifier_while[mod] expr_value[cond_expr]
{
- clear_block_exit(p, 0);
+ clear_block_exit(p, false);
if ($body && nd_type_p($body, NODE_BEGIN)) {
$$ = NEW_WHILE(cond(p, $cond_expr, &@cond_expr), RNODE_BEGIN($body)->nd_body, 0, &@$, &@mod, &NULL_LOC);
}
@@ -3401,7 +3383,7 @@ stmt : keyword_alias[kw] fitem[new] {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fit
}
| k_END[k_end] block_open[lbrace] compstmt(stmts)[body] '}'[rbrace]
{
- clear_block_exit(p, exits_mask(NODE_BREAK) | exits_mask(NODE_REDO));
+ clear_block_exit(p, true);
restore_block_exit(p, $block_open);
p->ctxt = $k_end;
{
diff --git a/prism/prism.c b/prism/prism.c
index 800d1eb105..df8d0d7f83 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -15332,9 +15332,6 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
return;
}
- if (PM_NODE_TYPE_P(node, PM_NEXT_NODE)) {
- return;
- }
}
PRISM_FALLTHROUGH
case PM_CONTEXT_DEF:
diff --git a/test/prism/errors/4.1/end_block_exit.txt b/test/prism/errors/4.1/end_block_exit.txt
index f8fc59d1a3..a4a1e9bc2c 100644
--- a/test/prism/errors/4.1/end_block_exit.txt
+++ b/test/prism/errors/4.1/end_block_exit.txt
@@ -3,3 +3,8 @@ END {
^~~~~ Invalid break
}
+END {
+ next
+ ^~~~ Invalid next
+}
+
diff --git a/test/prism/fixtures/3.3-4.0/end_block_exit.txt b/test/prism/fixtures/3.3-4.0/end_block_exit.txt
index 53afa1e2f4..8ebf0d6369 100644
--- a/test/prism/fixtures/3.3-4.0/end_block_exit.txt
+++ b/test/prism/fixtures/3.3-4.0/end_block_exit.txt
@@ -5,3 +5,7 @@ END {
END {
break
}
+
+END {
+ next
+}
diff --git a/test/prism/fixtures/end_block_exit.txt b/test/prism/fixtures/end_block_exit.txt
deleted file mode 100644
index 1f64dcb6ed..0000000000
--- a/test/prism/fixtures/end_block_exit.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-END {
- next
-}
diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb
index a59ce277d1..8b9a3f615d 100644
--- a/test/ruby/test_ast.rb
+++ b/test/ruby/test_ast.rb
@@ -255,11 +255,8 @@ class TestAst < Test::Unit::TestCase
assert_invalid_parse(msg, "#{code}")
assert_invalid_parse(msg, "def m; #{code}; end")
assert_invalid_parse(msg, "begin; #{code}; end")
- if code.start_with?("next")
- assert_parse("END {#{code}}")
- else
- assert_invalid_parse(msg, "END {#{code}}")
- end
+ assert_invalid_parse(msg, "BEGIN {#{code}}")
+ assert_invalid_parse(msg, "END {#{code}}")
assert_parse("!defined?(#{code})")
assert_parse("def m; defined?(#{code}); end")