diff options
author | Jeremy Evans <[email protected]> | 2024-09-18 16:54:56 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2024-09-18 16:54:56 -0700 |
commit | 268c72377b06b7d84a0998ca241340d0f58768f6 (patch) | |
tree | 517bcd762780681b88a2cea5d6318b7a244a6144 | |
parent | 984a791d58ec4350d62714a2d063c1bb54707bb6 (diff) |
Raise a compile error for break/next/redo inside eval in cases where it is optimized away
In cases where break/next/redo are not valid syntax, they should
raise a SyntaxError even if inside a conditional block that is
optimized away.
Fixes [Bug #20597]
Co-authored-by: Kevin Newton <[email protected]>
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/11099
Merged-By: jeremyevans <[email protected]>
-rw-r--r-- | bootstraptest/test_eval.rb | 2 | ||||
-rw-r--r-- | parse.y | 2 | ||||
-rw-r--r-- | prism/prism.c | 6 | ||||
-rw-r--r-- | prism_compile.c | 6 | ||||
-rw-r--r-- | test/ruby/test_eval.rb | 6 |
5 files changed, 14 insertions, 8 deletions
diff --git a/bootstraptest/test_eval.rb b/bootstraptest/test_eval.rb index d923a957bc..20bd9615f4 100644 --- a/bootstraptest/test_eval.rb +++ b/bootstraptest/test_eval.rb @@ -217,7 +217,7 @@ assert_equal %q{[10, main]}, %q{ } %w[break next redo].each do |keyword| - assert_match %r"Can't escape from eval with #{keyword}\b", %{ + assert_match %r"Invalid #{keyword}\b", %{ $stderr = STDOUT begin eval "0 rescue #{keyword}" @@ -1836,7 +1836,7 @@ clear_block_exit(struct parser_params *p, bool error) { rb_node_exits_t *exits = p->exits; if (!exits) return; - if (error && !compile_for_eval) { + if (error) { for (NODE *e = RNODE(exits); (e = RNODE_EXITS(e)->nd_chain) != 0; ) { switch (nd_type(e)) { case NODE_BREAK: diff --git a/prism/prism.c b/prism/prism.c index 54061d157d..1cbacf00d3 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -18852,12 +18852,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b switch (keyword.type) { case PM_TOKEN_KEYWORD_BREAK: { pm_node_t *node = (pm_node_t *) pm_break_node_create(parser, &keyword, arguments.arguments); - if (!parser->parsing_eval) parse_block_exit(parser, node); + parse_block_exit(parser, node); return node; } case PM_TOKEN_KEYWORD_NEXT: { pm_node_t *node = (pm_node_t *) pm_next_node_create(parser, &keyword, arguments.arguments); - if (!parser->parsing_eval) parse_block_exit(parser, node); + parse_block_exit(parser, node); return node; } case PM_TOKEN_KEYWORD_RETURN: { @@ -19574,7 +19574,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_node_t *node = (pm_node_t *) pm_redo_node_create(parser, &parser->previous); - if (!parser->parsing_eval) parse_block_exit(parser, node); + parse_block_exit(parser, node); return node; } diff --git a/prism_compile.c b/prism_compile.c index 435737cb66..76d4e05fbe 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -7275,7 +7275,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, throw_flag = 0; } else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) { - COMPILE_ERROR(iseq, location.line, "Can't escape from eval with break"); + COMPILE_ERROR(iseq, location.line, "Invalid break"); return; } else { @@ -9047,7 +9047,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, break; } else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) { - COMPILE_ERROR(iseq, location.line, "Can't escape from eval with next"); + COMPILE_ERROR(iseq, location.line, "Invalid next"); return; } @@ -9300,7 +9300,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, break; } else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) { - COMPILE_ERROR(iseq, location.line, "Can't escape from eval with redo"); + COMPILE_ERROR(iseq, location.line, "Invalid redo"); return; } diff --git a/test/ruby/test_eval.rb b/test/ruby/test_eval.rb index 082d1dc03c..cf1c2bb2f6 100644 --- a/test/ruby/test_eval.rb +++ b/test/ruby/test_eval.rb @@ -535,6 +535,12 @@ class TestEval < Test::Unit::TestCase assert_equal(fname, eval("__FILE__", nil, fname, 1)) end + def test_eval_invalid_block_exit_bug_20597 + assert_raise(SyntaxError){eval("break if false")} + assert_raise(SyntaxError){eval("next if false")} + assert_raise(SyntaxError){eval("redo if false")} + end + def test_eval_location_fstring o = Object.new o.instance_eval "def foo() end", "generated code" |