From ef697388becedf36966a2edcdcf88baca342b9e2 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Wed, 2 Oct 2019 07:56:28 -0700 Subject: [PATCH] Treat return in block in class/module as LocalJumpError (#2511) return directly in class/module is an error, so return in proc in class/module should also be an error. I believe the previous behavior was an unintentional oversight during the addition of top-level return in 2.4. --- spec/ruby/language/return_spec.rb | 21 +++++++++++---------- test/ruby/test_syntax.rb | 4 ++++ vm_insnhelper.c | 6 +++++- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/spec/ruby/language/return_spec.rb b/spec/ruby/language/return_spec.rb index 7f740be25b..7eef6d06ca 100644 --- a/spec/ruby/language/return_spec.rb +++ b/spec/ruby/language/return_spec.rb @@ -443,17 +443,18 @@ describe "The return keyword" do end describe "within a block within a class" do - it "is allowed" do - File.write(@filename, <<-END_OF_CODE) - class ReturnSpecs::A - ScratchPad << "before return" - 1.times { return } - ScratchPad << "after return" - end - END_OF_CODE + ruby_version_is "2.7" do + it "is not allowed" do + File.write(@filename, <<-END_OF_CODE) + class ReturnSpecs::A + ScratchPad << "before return" + 1.times { return } + ScratchPad << "after return" + end + END_OF_CODE - load @filename - ScratchPad.recorded.should == ["before return"] + -> { load @filename }.should raise_error(LocalJumpError) + end end end diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index a64d25845a..80bff868f6 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -1272,6 +1272,10 @@ eom assert_warn(/argument of top-level return is ignored/) {eval("return 1")} end + def test_return_in_proc_in_class + assert_in_out_err(['-e', 'class TestSyntax; proc{ return }.call; end'], "", [], /^-e:1:.*unexpected return \(LocalJumpError\)/) + end + def test_syntax_error_in_rescue bug12613 = '[ruby-core:76531] [Bug #12613]' assert_syntax_error("#{<<-"begin;"}\n#{<<-"end;"}", /Invalid retry/, bug12613) diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 76bc56d316..ef5a6db1af 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1258,7 +1258,10 @@ vm_throw_start(const rb_execution_context_t *ec, rb_control_frame_t *const reg_c switch (escape_cfp->iseq->body->type) { case ISEQ_TYPE_TOP: case ISEQ_TYPE_MAIN: - if (toplevel) goto valid_return; + if (toplevel) { + if (in_class_frame) goto unexpected_return; + goto valid_return; + } break; case ISEQ_TYPE_EVAL: case ISEQ_TYPE_CLASS: @@ -1276,6 +1279,7 @@ vm_throw_start(const rb_execution_context_t *ec, rb_control_frame_t *const reg_c escape_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(escape_cfp); } + unexpected_return:; rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN); valid_return:;