Skip to content

Commit 2f9432d

Browse files
committed
[Bug #20409] Make break and redo in END syntax error
1 parent 803b316 commit 2f9432d

2 files changed

Lines changed: 33 additions & 10 deletions

File tree

parse.y

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,7 +1659,22 @@ static NODE *add_block_exit(struct parser_params *p, NODE *node);
16591659
static rb_node_exits_t *init_block_exit(struct parser_params *p);
16601660
static rb_node_exits_t *allow_block_exit(struct parser_params *p);
16611661
static void restore_block_exit(struct parser_params *p, rb_node_exits_t *exits);
1662-
static void clear_block_exit(struct parser_params *p, bool error);
1662+
static void clear_block_exit(struct parser_params *p, unsigned int error_mask);
1663+
1664+
static unsigned int
1665+
exits_mask(enum node_type t)
1666+
{
1667+
switch (t) {
1668+
case NODE_BREAK:
1669+
case NODE_NEXT:
1670+
case NODE_REDO:
1671+
return 1u << (t - NODE_BREAK);
1672+
default:
1673+
UNREACHABLE_RETURN(0);
1674+
}
1675+
}
1676+
1677+
#define EXITS_MASK_ALL (exits_mask(NODE_BREAK)|exits_mask(NODE_NEXT)|exits_mask(NODE_REDO))
16631678

16641679
static void
16651680
next_rescue_context(struct lex_context *next, const struct lex_context *outer, enum rescue_context def)
@@ -1677,7 +1692,7 @@ restore_defun(struct parser_params *p, rb_node_def_temp_t *temp)
16771692
p->ctxt.in_rescue = ctxt.in_rescue;
16781693
p->max_numparam = temp->save.max_numparam;
16791694
numparam_pop(p, temp->save.numparam_save);
1680-
clear_block_exit(p, true);
1695+
clear_block_exit(p, EXITS_MASK_ALL);
16811696
}
16821697

16831698
static void
@@ -1834,20 +1849,23 @@ restore_block_exit(struct parser_params *p, rb_node_exits_t *exits)
18341849
}
18351850

18361851
static void
1837-
clear_block_exit(struct parser_params *p, bool error)
1852+
clear_block_exit(struct parser_params *p, unsigned int error_mask)
18381853
{
18391854
rb_node_exits_t *exits = p->exits;
18401855
if (!exits) return;
1841-
if (error) {
1856+
if (error_mask) {
18421857
for (NODE *e = RNODE(exits); (e = RNODE_EXITS(e)->nd_chain) != 0; ) {
18431858
switch (nd_type(e)) {
18441859
case NODE_BREAK:
1860+
if (!(error_mask & exits_mask(NODE_BREAK))) break;
18451861
yyerror1(&e->nd_loc, "Invalid break");
18461862
break;
18471863
case NODE_NEXT:
1864+
if (!(error_mask & exits_mask(NODE_NEXT))) break;
18481865
yyerror1(&e->nd_loc, "Invalid next");
18491866
break;
18501867
case NODE_REDO:
1868+
if (!(error_mask & exits_mask(NODE_REDO))) break;
18511869
yyerror1(&e->nd_loc, "Invalid redo");
18521870
break;
18531871
default:
@@ -3212,7 +3230,7 @@ top_stmts : none
32123230

32133231
top_stmt : stmt
32143232
{
3215-
clear_block_exit(p, true);
3233+
clear_block_exit(p, EXITS_MASK_ALL);
32163234
$$ = $1;
32173235
}
32183236
| keyword_BEGIN begin_block
@@ -3352,7 +3370,7 @@ stmt : keyword_alias[kw] fitem[new] {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fit
33523370
}
33533371
| stmt[body] modifier_while[mod] expr_value[cond_expr]
33543372
{
3355-
clear_block_exit(p, false);
3373+
clear_block_exit(p, 0);
33563374
if ($body && nd_type_p($body, NODE_BEGIN)) {
33573375
$$ = NEW_WHILE(cond(p, $cond_expr, &@cond_expr), RNODE_BEGIN($body)->nd_body, 0, &@$, &@mod, &NULL_LOC);
33583376
}
@@ -3363,7 +3381,7 @@ stmt : keyword_alias[kw] fitem[new] {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fit
33633381
}
33643382
| stmt[body] modifier_until[mod] expr_value[cond_expr]
33653383
{
3366-
clear_block_exit(p, false);
3384+
clear_block_exit(p, 0);
33673385
if ($body && nd_type_p($body, NODE_BEGIN)) {
33683386
$$ = NEW_UNTIL(cond(p, $cond_expr, &@cond_expr), RNODE_BEGIN($body)->nd_body, 0, &@$, &@mod, &NULL_LOC);
33693387
}
@@ -3381,9 +3399,10 @@ stmt : keyword_alias[kw] fitem[new] {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fit
33813399
$$ = NEW_RESCUE(remove_begin($body), resq, 0, &@$);
33823400
/*% ripper: rescue_mod!($:body, $:resbody) %*/
33833401
}
3384-
| k_END[k_end] allow_exits[allow] '{'[lbrace] compstmt(stmts)[body] '}'[rbrace]
3402+
| k_END[k_end] block_open[lbrace] compstmt(stmts)[body] '}'[rbrace]
33853403
{
3386-
restore_block_exit(p, $allow);
3404+
clear_block_exit(p, exits_mask(NODE_BREAK) | exits_mask(NODE_REDO));
3405+
restore_block_exit(p, $block_open);
33873406
p->ctxt = $k_end;
33883407
{
33893408
NODE *scope = NEW_SCOPE2(0 /* tbl */, 0 /* args */, $body /* body */, NULL /* parent */, &@$);

test/ruby/test_ast.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,11 @@ def test_invalid_exit
255255
assert_invalid_parse(msg, "#{code}")
256256
assert_invalid_parse(msg, "def m; #{code}; end")
257257
assert_invalid_parse(msg, "begin; #{code}; end")
258-
assert_parse("END {#{code}}")
258+
if code.start_with?("next")
259+
assert_parse("END {#{code}}")
260+
else
261+
assert_invalid_parse(msg, "END {#{code}}")
262+
end
259263

260264
assert_parse("!defined?(#{code})")
261265
assert_parse("def m; defined?(#{code}); end")

0 commit comments

Comments
 (0)