diff --git a/test/ruby/test_nomethod_error.rb b/test/ruby/test_nomethod_error.rb index 6d413e6391..aa2a88b2d8 100644 --- a/test/ruby/test_nomethod_error.rb +++ b/test/ruby/test_nomethod_error.rb @@ -106,4 +106,32 @@ class TestNoMethodError < Test::Unit::TestCase assert_match(/undefined method.+this_method_does_not_exist.+for.+Module/, err.to_s) end + + def test_send_forward_raises + t = EnvUtil.labeled_class("Test") do + def foo(...) + forward(...) + end + end + obj = t.new + assert_raise(NoMethodError) do + obj.foo + end + end + + # [Bug #21535] + def test_send_forward_raises_when_called_through_vcall + t = EnvUtil.labeled_class("Test") do + def foo(...) + forward(...) + end + def foo_indirect + foo # vcall + end + end + obj = t.new + assert_raise(NoMethodError) do + obj.foo_indirect + end + end end diff --git a/vm_insnhelper.c b/vm_insnhelper.c index c9e20e95b4..ac08a00600 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -4185,7 +4185,7 @@ static enum method_missing_reason ci_missing_reason(const struct rb_callinfo *ci) { enum method_missing_reason stat = MISSING_NOENTRY; - if (vm_ci_flag(ci) & VM_CALL_VCALL) stat |= MISSING_VCALL; + if (vm_ci_flag(ci) & VM_CALL_VCALL && !(vm_ci_flag(ci) & VM_CALL_FORWARDING)) stat |= MISSING_VCALL; if (vm_ci_flag(ci) & VM_CALL_FCALL) stat |= MISSING_FCALL; if (vm_ci_flag(ci) & VM_CALL_SUPER) stat |= MISSING_SUPER; return stat;