diff --git a/class.c b/class.c index 736e227925..4129647bdc 100644 --- a/class.c +++ b/class.c @@ -921,6 +921,7 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super) } iclass = rb_include_class_new(module, RCLASS_SUPER(c)); c = RCLASS_SET_SUPER(c, iclass); + RCLASS_SET_INCLUDER(iclass, klass); { VALUE m = module; diff --git a/internal.h b/internal.h index 374db5c0a4..3bd95c2c25 100644 --- a/internal.h +++ b/internal.h @@ -1039,6 +1039,7 @@ struct rb_classext_struct { const VALUE origin_; const VALUE refined_class; rb_alloc_func_t allocator; + const VALUE includer; }; typedef struct rb_classext_struct rb_classext_t; @@ -1078,6 +1079,7 @@ int rb_singleton_class_internal_p(VALUE sklass); #else # define RCLASS_SERIAL(c) (RCLASS_EXT(c)->class_serial) #endif +#define RCLASS_INCLUDER(c) (RCLASS_EXT(c)->includer) #define RCLASS_CLONED FL_USER6 #define RICLASS_IS_ORIGIN FL_USER5 @@ -1090,6 +1092,12 @@ RCLASS_SET_ORIGIN(VALUE klass, VALUE origin) if (klass != origin) FL_SET(origin, RICLASS_IS_ORIGIN); } +static inline void +RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass) +{ + RB_OBJ_WRITE(iclass, &RCLASS_INCLUDER(iclass), klass); +} + #undef RCLASS_SUPER static inline VALUE RCLASS_SUPER(VALUE klass) diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb index bb78ab516f..bbfc581500 100644 --- a/test/ruby/test_super.rb +++ b/test/ruby/test_super.rb @@ -307,6 +307,29 @@ class TestSuper < Test::Unit::TestCase end end + def test_super_in_instance_eval_in_module + super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { + def foo + return [:super, self] + end + } + mod = EnvUtil.labeled_module("Mod\u{30af 30e9 30b9}") { + def foo + x = Object.new + x.instance_eval do + super() + end + end + } + sub_class = EnvUtil.labeled_class("Sub\u{30af 30e9 30b9}", super_class) { + include mod + } + obj = sub_class.new + assert_raise_with_message(TypeError, /Sub\u{30af 30e9 30b9}/) do + obj.foo + end + end + def test_super_in_orphan_block super_class = EnvUtil.labeled_class("Super\u{30af 30e9 30b9}") { def foo diff --git a/vm_insnhelper.c b/vm_insnhelper.c index c8ea3f9b1b..8487886886 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -3126,16 +3126,17 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c } if (BUILTIN_TYPE(current_defined_class) != T_MODULE && - BUILTIN_TYPE(current_defined_class) != T_ICLASS && /* bound UnboundMethod */ !FL_TEST(current_defined_class, RMODULE_INCLUDED_INTO_REFINEMENT) && !rb_obj_is_kind_of(recv, current_defined_class)) { VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ? - RBASIC(current_defined_class)->klass : current_defined_class; + RCLASS_INCLUDER(current_defined_class) : current_defined_class; - rb_raise(rb_eTypeError, - "self has wrong type to call super in this context: " - "%"PRIsVALUE" (expected %"PRIsVALUE")", - rb_obj_class(recv), m); + if (m) { /* not bound UnboundMethod */ + rb_raise(rb_eTypeError, + "self has wrong type to call super in this context: " + "%"PRIsVALUE" (expected %"PRIsVALUE")", + rb_obj_class(recv), m); + } } if (me->def->type == VM_METHOD_TYPE_BMETHOD && (ci->flag & VM_CALL_ZSUPER)) {