From 7a288df7b85d3565f369b305f225c2cd5baa5905 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Tue, 11 Feb 2020 11:56:34 -0800 Subject: [PATCH] Make yield in singleton class definitions in methods a SyntaxError This behavior was deprecated in 2.7 and scheduled to be removed in 3.0. Calling yield in a class definition outside a method is now a SyntaxError instead of a LocalJumpError, as well. --- NEWS.md | 2 ++ bootstraptest/test_jump.rb | 23 ++++++++++++++--------- compile.c | 13 +++---------- spec/ruby/language/class_spec.rb | 10 +++++++++- test/ruby/test_class.rb | 2 +- 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/NEWS.md b/NEWS.md index f6bd2a4bb2..22943d64a7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,8 @@ sufficient information, see the ChangeLog file or Redmine * $SAFE is now a normal global variable with no special behavior. [Feature #16131] +* yield in singleton class definitions in methods is now a SyntaxError. [Feature #15575] + ## Command line options ## Core classes updates (outstanding ones only) diff --git a/bootstraptest/test_jump.rb b/bootstraptest/test_jump.rb index 7944915862..18a2737ea3 100644 --- a/bootstraptest/test_jump.rb +++ b/bootstraptest/test_jump.rb @@ -296,14 +296,19 @@ assert_equal "true", %q{ s.return_eigenclass == class << s; self; end }, '[ruby-core:21379]' -assert_equal "true", %q{ - class Object - def yield_eigenclass - class << self - yield self +assert_match %r{Invalid yield}, %q{ +STDERR.reopen(STDOUT) +begin + eval %q{ + class Object + def yield_eigenclass + class << self + yield self + end end end - end - s = "foo" - s.yield_eigenclass {|c| c == class << s; self; end } -}, '[ruby-dev:40975]' + } +rescue SyntaxError => e + e.message +end +} diff --git a/compile.c b/compile.c index e57ad4498a..e9ce106eca 100644 --- a/compile.c +++ b/compile.c @@ -7096,20 +7096,13 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int poppe } static int -check_yield_place(const rb_iseq_t *iseq, int line) +check_yield_place(const rb_iseq_t *iseq) { - VALUE file; switch (iseq->body->local_iseq->body->type) { case ISEQ_TYPE_TOP: case ISEQ_TYPE_MAIN: - return FALSE; case ISEQ_TYPE_CLASS: - file = rb_iseq_path(iseq); - if (rb_warning_category_enabled_p(RB_WARN_CATEGORY_DEPRECATED)) { - rb_compile_warn(RSTRING_PTR(file), line, - "`yield' in class syntax will not be supported from Ruby 3.0. [Feature #15575]"); - } - return TRUE; + return FALSE; default: return TRUE; } @@ -7836,7 +7829,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in INIT_ANCHOR(args); - if (check_yield_place(iseq, line) == FALSE) { + if (check_yield_place(iseq) == FALSE) { COMPILE_ERROR(ERROR_ARGS "Invalid yield"); goto ng; } diff --git a/spec/ruby/language/class_spec.rb b/spec/ruby/language/class_spec.rb index 88b7a6a74f..2b9a4afef7 100644 --- a/spec/ruby/language/class_spec.rb +++ b/spec/ruby/language/class_spec.rb @@ -285,7 +285,7 @@ describe "A class definition extending an object (sclass)" do }.should raise_error(TypeError) end - ruby_version_is ""..."3.0" do + ruby_version_is ""..."2.8" do it "allows accessing the block of the original scope" do suppress_warning do ClassSpecs.sclass_with_block { 123 }.should == 123 @@ -293,6 +293,14 @@ describe "A class definition extending an object (sclass)" do end end + ruby_version_is "2.8" do + it "does not allow accessing the block of the original scope" do + -> { + ClassSpecs.sclass_with_block { 123 } + }.should raise_error(SyntaxError) + end + end + it "can use return to cause the enclosing method to return" do ClassSpecs.sclass_with_return.should == :inner end diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb index ca78473026..82a2e55634 100644 --- a/test/ruby/test_class.rb +++ b/test/ruby/test_class.rb @@ -312,7 +312,7 @@ class TestClass < Test::Unit::TestCase end def test_invalid_yield_from_class_definition - assert_raise(LocalJumpError) { + assert_raise(SyntaxError) { EnvUtil.suppress_warning {eval("class C; yield; end")} } end