summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <[email protected]>2024-09-18 16:54:56 -0700
committerGitHub <[email protected]>2024-09-18 16:54:56 -0700
commit268c72377b06b7d84a0998ca241340d0f58768f6 (patch)
tree517bcd762780681b88a2cea5d6318b7a244a6144
parent984a791d58ec4350d62714a2d063c1bb54707bb6 (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.rb2
-rw-r--r--parse.y2
-rw-r--r--prism/prism.c6
-rw-r--r--prism_compile.c6
-rw-r--r--test/ruby/test_eval.rb6
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}"
diff --git a/parse.y b/parse.y
index 134c80cdd2..435741a608 100644
--- a/parse.y
+++ b/parse.y
@@ -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"