зеркало из https://github.com/github/ruby.git
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 <kddnewton@gmail.com>
This commit is contained in:
Родитель
984a791d58
Коммит
268c72377b
|
@ -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}"
|
||||
|
|
2
parse.y
2
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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
Загрузка…
Ссылка в новой задаче