diff --git a/src/prism.c b/src/prism.c index 0d9d73349a0..285319ca91c 100644 --- a/src/prism.c +++ b/src/prism.c @@ -15342,6 +15342,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept */ static void parse_return(pm_parser_t *parser, pm_node_t *node) { + bool in_sclass = false; for (pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) { switch (context_node->context) { case PM_CONTEXT_BEGIN_ELSE: @@ -15366,10 +15367,6 @@ parse_return(pm_parser_t *parser, pm_node_t *node) { case PM_CONTEXT_PREDICATE: case PM_CONTEXT_PREEXE: case PM_CONTEXT_RESCUE_MODIFIER: - case PM_CONTEXT_SCLASS_ELSE: - case PM_CONTEXT_SCLASS_ENSURE: - case PM_CONTEXT_SCLASS_RESCUE: - case PM_CONTEXT_SCLASS: case PM_CONTEXT_TERNARY: case PM_CONTEXT_UNLESS: case PM_CONTEXT_UNTIL: @@ -15377,6 +15374,12 @@ parse_return(pm_parser_t *parser, pm_node_t *node) { // Keep iterating up the lists of contexts, because returns can // see through these. continue; + case PM_CONTEXT_SCLASS_ELSE: + case PM_CONTEXT_SCLASS_ENSURE: + case PM_CONTEXT_SCLASS_RESCUE: + case PM_CONTEXT_SCLASS: + in_sclass = true; + continue; case PM_CONTEXT_CLASS_ELSE: case PM_CONTEXT_CLASS_ENSURE: case PM_CONTEXT_CLASS_RESCUE: @@ -15411,6 +15414,9 @@ parse_return(pm_parser_t *parser, pm_node_t *node) { break; } } + if (in_sclass) { + pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID); + } } /** diff --git a/test/prism/errors/dont_allow_return_inside_sclass_body.txt b/test/prism/errors/dont_allow_return_inside_sclass_body.txt new file mode 100644 index 00000000000..c29fe017282 --- /dev/null +++ b/test/prism/errors/dont_allow_return_inside_sclass_body.txt @@ -0,0 +1,3 @@ +class << A; return; end + ^~~~~~ Invalid return in class/module body + diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb index 9a108ceca7c..f46cb942a20 100644 --- a/test/prism/errors_test.rb +++ b/test/prism/errors_test.rb @@ -19,9 +19,11 @@ class ErrorsTest < TestCase end if RUBY_VERSION < "3.4" - filepaths -= [ - "it_with_ordinary_parameter.txt" - ] + filepaths -= ["it_with_ordinary_parameter.txt"] + end + + if RUBY_VERSION < "3.4" || RUBY_RELEASE_DATE < "2024-07-24" + filepaths -= ["dont_allow_return_inside_sclass_body.txt"] end filepaths.each do |filepath|